[clang-tools-extra] [llvm] [clang] [llvm-objcopy] Add --gap-fill and --pad-to options (PR #65815)

via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 13 11:18:27 PST 2023


https://github.com/quic-akaryaki updated https://github.com/llvm/llvm-project/pull/65815

>From 21ba98fbed6ef3b9bbbef96feb6dfeb0679f7ce8 Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Tue, 5 Sep 2023 15:46:34 -0700
Subject: [PATCH 1/6] [llvm-objcopy] Add --gap-fill and --pad-to options

`--gap-fill <value>` fills the gaps between sections with a specified
8-bit value, instead of zero.
`--pad-to <address>` pads the output binary up to the specified load
address, using the 8-bit value from `--gap-fill` or zero.

These options are only supported for ELF inputs and binary outputs.
---
 llvm/docs/CommandGuide/llvm-objcopy.rst       |  10 ++
 llvm/include/llvm/ObjCopy/CommonConfig.h      |   2 +
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp           |   2 +-
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            |  31 +++-
 llvm/lib/ObjCopy/ELF/ELFObject.h              |   5 +-
 .../llvm-objcopy/ELF/gap-fill-order.test      |  34 ++++
 .../test/tools/llvm-objcopy/ELF/gap-fill.test | 149 ++++++++++++++++++
 llvm/test/tools/llvm-objcopy/ELF/pad-to.test  |  84 ++++++++++
 llvm/tools/llvm-objcopy/ObjcopyOptions.cpp    |  25 +++
 llvm/tools/llvm-objcopy/ObjcopyOpts.td        |  12 ++
 10 files changed, 350 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test
 create mode 100644 llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
 create mode 100644 llvm/test/tools/llvm-objcopy/ELF/pad-to.test

diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index 0233a4f7b2f045f..6e13cd94b92fdaf 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -324,6 +324,11 @@ them.
 
  Extract the named partition from the output.
 
+.. option:: --gap-fill <value>
+
+ For binary outputs, fill the gaps between sections with ``<value>`` instead
+ of zero. The value must be an unsigned 8-bit integer.
+
 .. option:: --globalize-symbol <symbol>
 
  Mark any defined symbols named ``<symbol>`` as global symbols in the output.
@@ -411,6 +416,11 @@ them.
  be the same as the value specified for :option:`--input-target` or the input
  file's format if that option is also unspecified.
 
+.. option:: --pad-to <address>
+
+ For binary outputs, pad the output to the load address ``<address>`` using a value
+ of zero or the value specified by :option:`--gap-fill`.
+
 .. option:: --prefix-alloc-sections <prefix>
 
  Add ``<prefix>`` to the front of the names of all allocatable sections in the
diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index e7ce1e6f2c54d75..ebfd404293400ea 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -214,6 +214,8 @@ struct CommonConfig {
   // Cached gnu_debuglink's target CRC
   uint32_t GnuDebugLinkCRC32;
   std::optional<StringRef> ExtractPartition;
+  uint8_t GapFill = 0;
+  std::optional<uint64_t> PadTo;
   StringRef SplitDWO;
   StringRef SymbolsPrefix;
   StringRef AllocSectionsPrefix;
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 58cb9cb65679b71..37d2af2139e317f 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -180,7 +180,7 @@ static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
                                             ElfType OutputElfType) {
   switch (Config.OutputFormat) {
   case FileFormat::Binary:
-    return std::make_unique<BinaryWriter>(Obj, Out);
+    return std::make_unique<BinaryWriter>(Obj, Out, Config);
   case FileFormat::IHex:
     return std::make_unique<IHexWriter>(Obj, Out);
   default:
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 697afab2a617b47..770923688832729 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2635,9 +2635,36 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
 }
 
 Error BinaryWriter::write() {
-  for (const SectionBase &Sec : Obj.allocSections())
+  SmallVector<const SectionBase *, 30> LoadableSections;
+  for (const SectionBase &Sec : Obj.allocSections()) {
+    if ((Sec.Flags & SectionFlag::SecLoad) && Sec.Type != SHT_NOBITS)
+      LoadableSections.push_back(&Sec);
+  }
+
+  if (LoadableSections.empty())
+    return Error::success();
+
+  llvm::stable_sort(LoadableSections,
+                    [](const SectionBase *LHS, const SectionBase *RHS) {
+                      return LHS->Offset < RHS->Offset;
+                    });
+
+  assert(LoadableSections.front()->Offset == 0);
+
+  for (unsigned i = 0; i != LoadableSections.size(); ++i) {
+    const SectionBase &Sec = *LoadableSections[i];
     if (Error Err = Sec.accept(*SecWriter))
       return Err;
+    if (GapFill == 0)
+      continue;
+    uint64_t PadOffset = (i < LoadableSections.size() - 1)
+                             ? LoadableSections[i + 1]->Offset
+                             : Buf->getBufferSize();
+    assert(PadOffset <= Buf->getBufferSize());
+    if (Sec.Offset + Sec.Size < PadOffset)
+      std::fill(Buf->getBufferStart() + Sec.Offset + Sec.Size,
+                Buf->getBufferStart() + PadOffset, GapFill);
+  }
 
   // TODO: Implement direct writing to the output stream (without intermediate
   // memory buffer Buf).
@@ -2663,7 +2690,7 @@ Error BinaryWriter::finalize() {
   // file size. This might not be the same as the offset returned by
   // layoutSections, because we want to truncate the last segment to the end of
   // its last non-empty section, to match GNU objcopy's behaviour.
-  TotalSize = 0;
+  TotalSize = PadTo && PadTo.value() > MinAddr ? PadTo.value() - MinAddr : 0;
   for (SectionBase &Sec : Obj.allocSections())
     if (Sec.Type != SHT_NOBITS && Sec.Size > 0) {
       Sec.Offset = Sec.Addr - MinAddr;
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 89a03b3fe0ee354..bf6fa32908e3dcf 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -357,6 +357,8 @@ template <class ELFT> class ELFWriter : public Writer {
 
 class BinaryWriter : public Writer {
 private:
+  const uint8_t GapFill;
+  const std::optional<uint64_t> PadTo;
   std::unique_ptr<BinarySectionWriter> SecWriter;
 
   uint64_t TotalSize = 0;
@@ -365,7 +367,8 @@ class BinaryWriter : public Writer {
   ~BinaryWriter() {}
   Error finalize() override;
   Error write() override;
-  BinaryWriter(Object &Obj, raw_ostream &Out) : Writer(Obj, Out) {}
+  BinaryWriter(Object &Obj, raw_ostream &Out, const CommonConfig &Config)
+      : Writer(Obj, Out), GapFill(Config.GapFill), PadTo(Config.PadTo) {}
 };
 
 class IHexWriter : public Writer {
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test
new file mode 100644
index 000000000000000..4b0ecad5cd3bfa4
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test
@@ -0,0 +1,34 @@
+# RUN: yaml2obj %s >%t
+
+# Test gap fill with all allocatable output sections
+# RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck --match-full-lines %s
+# CHECK: 000000 aa bb cc dd e9 e9 e9 e9 11 22 33 44
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_HEXAGON
+Sections:
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x0104
+    AddressAlign:    0x0001
+    Size:            4
+  - Name:            .section1
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x0108
+    AddressAlign:    0x0001
+    Content:         '11223344'
+  - Name:            .section3
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x0100
+    AddressAlign:    0x0001
+    Content:         'AABBCCDD'
+...
+
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
new file mode 100644
index 000000000000000..4edeb3905060541
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -0,0 +1,149 @@
+# RUN: yaml2obj %s > %t
+
+## Verify section headers before we perform several testings.
+# RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=ORG-SHDR
+# ORG-SHDR: Section Headers:
+# ORG-SHDR:  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
+# ORG-SHDR:  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
+# ORG-SHDR:  [ 1] .nogap            PROGBITS        0000000000000102 000042 000006 00   A  0   0  1
+# ORG-SHDR:  [ 2] .gap1             PROGBITS        0000000000000108 000048 000007 00  AX  0   0  1
+# ORG-SHDR:  [ 3] .gap2             PROGBITS        0000000000000110 000050 000004 00   A  0   0  1
+# ORG-SHDR:  [ 4] .nobit_tbss       NOBITS          0000000000000180 000058 000018 00 WAT  0   0  8
+# ORG-SHDR:  [ 5] .foo              PROGBITS        0000000000000184 00005c 000004 00  WA  0   0  1
+# ORG-SHDR:  [ 6] .nobit_bss        NOBITS          000000000000018a 000060 000008 00  WA  0   0  1
+
+# RUN: not llvm-objcopy --gap-fill 1 %t 2>&1 | FileCheck %s --check-prefix=NOT-BINARY
+# NOT-BINARY: error: '--gap-fill' is only supported for binary output
+
+# RUN: not llvm-objcopy -O binary --gap-fill %t 2>&1 | FileCheck %s --check-prefix=EMPTY
+# EMPTY: no input file specified
+
+# RUN: not llvm-objcopy -O binary --gap-fill= %t 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
+# BAD-FORMAT: bad number for --gap-fill:
+
+# RUN: not llvm-objcopy -O binary --gap-fill=x %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT
+# BAD-INPUT: bad number for --gap-fill: x
+
+# RUN: not llvm-objcopy -O binary --gap-fill=0x1G %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT2
+# BAD-INPUT2: bad number for --gap-fill: 0x1G
+
+# RUN: not llvm-objcopy -O binary --gap-fill=0x1122 %t %t-val16 2>&1 | FileCheck %s --check-prefix=BAD-INPUT3
+# BAD-INPUT3: bad number for --gap-fill: 0x1122
+
+# Test no gap fill gap fill with all allocatable output sections
+# RUN: llvm-objcopy -O binary %t %t-default
+# RUN: od -v -Ax -t x1 %t-default | FileCheck %s --check-prefix=DEFAULT
+# DEFAULT: 000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba 00 a1 b2
+# DEFAULT-NEXT: 000010 c3 d4 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# DEFAULT-NEXT: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# DEFAULT-NEXT: 000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# DEFAULT-NEXT: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# DEFAULT-NEXT: 000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# DEFAULT-NEXT: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# DEFAULT-NEXT: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# DEFAULT-NEXT: 000080 00 00 89 ab cd ef
+# DEFAULT-NEXT: 000086
+
+# Test gap fill with all allocatable output sections
+# RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=FULL
+# FULL: 000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 a1 b2
+# FULL-NEXT: 000010 c3 d4 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# FULL-NEXT: 000020 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# FULL-NEXT: 000030 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# FULL-NEXT: 000040 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# FULL-NEXT: 000050 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# FULL-NEXT: 000060 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# FULL-NEXT: 000070 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# FULL-NEXT: 000080 e9 e9 89 ab cd ef
+# FULL-NEXT: 000086
+
+# Test gap fill with the last section removed, should be truncated
+# RUN: llvm-objcopy -O binary --gap-fill=0xe9 --remove-section=.foo %t %t-filled
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-LAST-SECTION
+# REMOVE-LAST-SECTION: 000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 a1 b2
+# REMOVE-LAST-SECTION-NEXT: 000010 c3 d4
+# REMOVE-LAST-SECTION-NEXT: 000012
+
+# Test gap fill with the middle section removed, should be filled
+# RUN: llvm-objcopy -O binary --gap-fill=0xe9 --remove-section=.gap2 %t %t-filled
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-MIDDLE-SECTION
+# REMOVE-MIDDLE-SECTION: 000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 e9 e9
+# REMOVE-MIDDLE-SECTION-NEXT: 000010 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-MIDDLE-SECTION-NEXT: 000020 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-MIDDLE-SECTION-NEXT: 000030 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-MIDDLE-SECTION-NEXT: 000040 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-MIDDLE-SECTION-NEXT: 000050 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-MIDDLE-SECTION-NEXT: 000060 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-MIDDLE-SECTION-NEXT: 000070 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-MIDDLE-SECTION-NEXT: 000080 e9 e9 89 ab cd ef
+# REMOVE-MIDDLE-SECTION-NEXT: 000086
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .space1
+    Type:            Fill
+    Pattern:         'ABCD'
+    Size:            0x2
+  - Name:            .nogap
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0102
+    AddressAlign:    0x0001
+    Size:            0x6
+    Content:         'EEFF11223344'
+  - Name:            .gap1
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0108
+    AddressAlign:    0x0001
+    Content:         'AABBCCDDFEDCBA'
+  - Name:            .space2
+    Type:            Fill
+    Pattern:         'DC'
+    Size:            1
+  - Name:            .gap2
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0110
+    AddressAlign:    0x0001
+    Content:         'A1B2C3D4'
+  - Name:            .space3
+    Type:            Fill
+    Pattern:         'FE'
+    Size:            0x1
+  - Name:            .nobit_tbss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+    Address:         0x0180
+    AddressAlign:    0x0008
+    Size:            0x0018
+  - Name:            .space4             # in the different segment
+    Type:            Fill
+    Pattern:         '01234567'
+    Size:            0x4
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x0184
+    AddressAlign:    0x0001
+    Content:         '89ABCDEF'
+  - Name:            .nobit_bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x018A
+    AddressAlign:    0x0001
+    Size:            0x0008
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0001
+    EntSize:         0x0001
+    Content:         4743433A
+
+...
diff --git a/llvm/test/tools/llvm-objcopy/ELF/pad-to.test b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
new file mode 100644
index 000000000000000..fb777ad750dbfe0
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
@@ -0,0 +1,84 @@
+# RUN: yaml2obj %s > %t
+
+# baseline, no padding
+# RUN: llvm-objcopy -O binary %t %t.bin
+
+# RUN: not llvm-objcopy --pad-to=1 %t 2>&1 | FileCheck %s --check-prefix=NOT-BINARY
+# NOT-BINARY: error: '--pad-to' is only supported for binary output
+
+# RUN: not llvm-objcopy -O binary --pad-to= %t 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
+# BAD-FORMAT: bad address for --pad-to:
+
+# RUN: not llvm-objcopy -O binary --pad-to=x %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT
+# BAD-INPUT: bad address for --pad-to: x
+
+# RUN: not llvm-objcopy -O binary --pad-to=0x1G %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT2
+# BAD-INPUT2: bad address for --pad-to: 0x1G
+
+# RUN: not llvm-objcopy -O binary --pad-to=0x112233445566778899 %t 2>&1 | FileCheck %s --check-prefix=BAD-NUMBER
+# BAD-NUMBER: bad address for --pad-to: 0x112233445566778899
+
+# Pad to a address smaller than the binary size
+# RUN: llvm-objcopy -O binary --pad-to=0x20 %t %t-p1
+# RUN: cmp %t.bin %t-p1
+# RUN: llvm-objcopy -O binary --pad-to=0x200 %t %t-p2
+# RUN: cmp %t.bin %t-p2
+
+## Pad all allocatable sections to a valid address.
+# RUN: llvm-objcopy -O binary --pad-to=0x218 %t %t-pad-default
+# RUN: od -v -Ax -t x1 %t-pad-default | FileCheck %s --check-prefix=DEFAULT
+# DEFAULT: 000000 11 22 33 44 55 66 00 00 00 00 00 00 00 00 00 00
+# DEFAULT-NEXT: 000010 77 88 99 aa 00 00 00 00
+# DEFAULT-NEXT: 000018
+
+## Pad all allocatable sections to a valid address, using --gap-fill.
+# RUN: llvm-objcopy -O binary --pad-to=0x218 --gap-fill=0xe9 %t %t-pad-fill
+# RUN: od -v -Ax -t x1 %t-pad-fill | FileCheck %s --check-prefix=FILL
+# FILL: 000000 11 22 33 44 55 66 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# FILL-NEXT: 000010 77 88 99 aa e9 e9 e9 e9
+# FILL-NEXT: 000018
+
+# Test gap fill with a section removed
+# RUN: llvm-objcopy -O binary --pad-to=0x218 --gap-fill=0xe9 --remove-section=.section2 %t %t-filled
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-SECTION
+# REMOVE-SECTION: 000000 11 22 33 44 55 66 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-SECTION-NEXT: 000010 e9 e9 e9 e9 e9 e9 e9 e9
+# REMOVE-SECTION-NEXT: 000018
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .section1
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0200
+    AddressAlign:    0x0001
+    Size:            0x6
+    Content:         '112233445566'
+  - Name:            .space
+    Type:            Fill
+    Pattern:         '01234567'
+    Size:            0x4
+  - Name:            .section2
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x0210
+    AddressAlign:    0x0001
+    Content:         '778899aa'
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x0220
+    AddressAlign:    0x0001
+    Size:            0x0008
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0001
+    EntSize:         0x0001
+    Content:         ''
+...
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index d33adb0b6a3e478..b4104053e2b3f91 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -738,6 +738,31 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
   if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
     Config.ExtractPartition = Arg->getValue();
 
+  if (const auto *A = InputArgs.getLastArg(OBJCOPY_gap_fill)) {
+    if (Config.OutputFormat != FileFormat::Binary)
+      return createStringError(
+          errc::invalid_argument,
+          "'--gap-fill' is only supported for binary output");
+    ErrorOr<uint8_t> Val = getAsInteger<uint8_t>(A->getValue());
+    if (!Val)
+      return createStringError(Val.getError(), "bad number for --gap-fill: %s",
+                               A->getValue());
+    Config.GapFill = Val.get();
+  } else
+    Config.GapFill = 0; // The value of zero is equivalent to no fill.
+
+  if (const auto *A = InputArgs.getLastArg(OBJCOPY_pad_to)) {
+    if (Config.OutputFormat != FileFormat::Binary)
+      return createStringError(
+          errc::invalid_argument,
+          "'--pad-to' is only supported for binary output");
+    ErrorOr<uint64_t> Addr = getAsInteger<uint64_t>(A->getValue());
+    if (!Addr)
+      return createStringError(Addr.getError(), "bad address for --pad-to: %s",
+                               A->getValue());
+    Config.PadTo = *Addr;
+  }
+
   for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
     if (!StringRef(Arg->getValue()).contains('='))
       return createStringError(errc::invalid_argument,
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index ea8828637222ac6..556f84e3154fe06 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -230,3 +230,15 @@ defm add_symbol
 defm update_section
     : Eq<"update-section", "Replace the contents of section <name> with contents from a file <file>">,
       MetaVarName<"name=file">;
+
+defm gap_fill
+    : Eq<"gap-fill", "Fill the gaps between sections with <value> instead of zero. "
+                     "<value> must be an unsigned 8-bit integer. "
+                     "This option is only supported for ELF inputs and binary outputs.">,
+      MetaVarName<"value">;
+
+defm pad_to
+    : Eq<"pad-to", "Pad the output to the load address <address>, using a value "
+                   "of zero or the value specified by :option:`--gap-fill`"
+                   "This option is only supported for ELF inputs and binary outputs.">,
+      MetaVarName<"address">;

>From c713cec1cefef2605c308278d75bfea0fb37146d Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Thu, 14 Sep 2023 08:14:37 -0700
Subject: [PATCH 2/6] Address PR feedback.

Change-Id: I7d57e3e87bd0393bbfe1b664228fe3bb0154d244
---
 llvm/docs/ReleaseNotes.rst                    |  3 +
 llvm/include/llvm/ObjCopy/CommonConfig.h      |  2 +-
 llvm/lib/ObjCopy/ConfigManager.cpp            | 12 ++--
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            | 12 ++--
 .../llvm-objcopy/ELF/gap-fill-order.test      | 12 ++--
 .../test/tools/llvm-objcopy/ELF/gap-fill.test | 68 ++++++++++---------
 llvm/test/tools/llvm-objcopy/ELF/pad-to.test  | 40 +++++++----
 llvm/tools/llvm-objcopy/ObjcopyOptions.cpp    | 16 +++--
 8 files changed, 98 insertions(+), 67 deletions(-)

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 226ee606d17ee22..bad5dbc8a102473 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -167,6 +167,9 @@ Changes to the LLVM tools
 * llvm-symbolizer now treats invalid input as an address for which source
   information is not found.
 
+* llvm-objcopy now supports ``--gap-fill`` and ``--pad-to`` options, for
+  ELF input and binary output files only.
+
 Changes to LLDB
 ---------------------------------
 
diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index ebfd404293400ea..386c20aec184ded 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -215,7 +215,7 @@ struct CommonConfig {
   uint32_t GnuDebugLinkCRC32;
   std::optional<StringRef> ExtractPartition;
   uint8_t GapFill = 0;
-  std::optional<uint64_t> PadTo;
+  uint64_t PadTo = 0;
   StringRef SplitDWO;
   StringRef SymbolsPrefix;
   StringRef AllocSectionsPrefix;
diff --git a/llvm/lib/ObjCopy/ConfigManager.cpp b/llvm/lib/ObjCopy/ConfigManager.cpp
index 5b8e2f5dc2003af..6074723279e8150 100644
--- a/llvm/lib/ObjCopy/ConfigManager.cpp
+++ b/llvm/lib/ObjCopy/ConfigManager.cpp
@@ -23,7 +23,8 @@ Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {
       Common.ExtractDWO || Common.PreserveDates || Common.StripDWO ||
       Common.StripNonAlloc || Common.StripSections || Common.Weaken ||
       Common.DecompressDebugSections ||
-      Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty())
+      Common.DiscardMode == DiscardType::Locals ||
+      !Common.SymbolsToAdd.empty() || Common.GapFill != 0 || Common.PadTo != 0)
     return createStringError(llvm::errc::invalid_argument,
                              "option is not supported for COFF");
 
@@ -42,7 +43,8 @@ Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
       Common.PreserveDates || Common.StripAllGNU || Common.StripDWO ||
       Common.StripNonAlloc || Common.StripSections || Common.Weaken ||
       Common.DecompressDebugSections || Common.StripUnneeded ||
-      Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty())
+      Common.DiscardMode == DiscardType::Locals ||
+      !Common.SymbolsToAdd.empty() || Common.GapFill != 0 || Common.PadTo != 0)
     return createStringError(llvm::errc::invalid_argument,
                              "option is not supported for MachO");
 
@@ -60,7 +62,8 @@ Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
       !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
       !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
       !Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() ||
-      !Common.SymbolsToRename.empty())
+      !Common.SymbolsToRename.empty() || Common.GapFill != 0 ||
+      Common.PadTo != 0)
     return createStringError(llvm::errc::invalid_argument,
                              "only flags for section dumping, removal, and "
                              "addition are supported");
@@ -86,7 +89,8 @@ Expected<const XCOFFConfig &> ConfigManager::getXCOFFConfig() const {
       Common.ExtractMainPartition || Common.OnlyKeepDebug ||
       Common.PreserveDates || Common.StripAllGNU || Common.StripDWO ||
       Common.StripDebug || Common.StripNonAlloc || Common.StripSections ||
-      Common.Weaken || Common.StripUnneeded || Common.DecompressDebugSections) {
+      Common.Weaken || Common.StripUnneeded || Common.DecompressDebugSections ||
+      Common.GapFill != 0 || Common.PadTo != 0) {
     return createStringError(
         llvm::errc::invalid_argument,
         "no flags are supported yet, only basic copying is allowed");
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 770923688832729..85a123d26ebfe42 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2637,7 +2637,7 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
 Error BinaryWriter::write() {
   SmallVector<const SectionBase *, 30> LoadableSections;
   for (const SectionBase &Sec : Obj.allocSections()) {
-    if ((Sec.Flags & SectionFlag::SecLoad) && Sec.Type != SHT_NOBITS)
+    if (Sec.Type != SHT_NOBITS)
       LoadableSections.push_back(&Sec);
   }
 
@@ -2651,7 +2651,7 @@ Error BinaryWriter::write() {
 
   assert(LoadableSections.front()->Offset == 0);
 
-  for (unsigned i = 0; i != LoadableSections.size(); ++i) {
+  for (std::size_t i = 0; i != LoadableSections.size(); ++i) {
     const SectionBase &Sec = *LoadableSections[i];
     if (Error Err = Sec.accept(*SecWriter))
       return Err;
@@ -2661,9 +2661,9 @@ Error BinaryWriter::write() {
                              ? LoadableSections[i + 1]->Offset
                              : Buf->getBufferSize();
     assert(PadOffset <= Buf->getBufferSize());
-    if (Sec.Offset + Sec.Size < PadOffset)
-      std::fill(Buf->getBufferStart() + Sec.Offset + Sec.Size,
-                Buf->getBufferStart() + PadOffset, GapFill);
+    assert(Sec.Offset + Sec.Size <= PadOffset);
+    std::fill(Buf->getBufferStart() + Sec.Offset + Sec.Size,
+              Buf->getBufferStart() + PadOffset, GapFill);
   }
 
   // TODO: Implement direct writing to the output stream (without intermediate
@@ -2690,7 +2690,7 @@ Error BinaryWriter::finalize() {
   // file size. This might not be the same as the offset returned by
   // layoutSections, because we want to truncate the last segment to the end of
   // its last non-empty section, to match GNU objcopy's behaviour.
-  TotalSize = PadTo && PadTo.value() > MinAddr ? PadTo.value() - MinAddr : 0;
+  TotalSize = PadTo.value() > MinAddr ? PadTo.value() - MinAddr : 0;
   for (SectionBase &Sec : Obj.allocSections())
     if (Sec.Type != SHT_NOBITS && Sec.Size > 0) {
       Sec.Offset = Sec.Addr - MinAddr;
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test
index 4b0ecad5cd3bfa4..c154617bd3cd317 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test
@@ -1,16 +1,19 @@
-# RUN: yaml2obj %s >%t
+# RUN: yaml2obj %s -o %t
+
+## In this test, output sections are defined out of
+## order in respect to their load addresses. Verify
+## that gaps are still correctly filled.
 
-# Test gap fill with all allocatable output sections
 # RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled
 # RUN: od -v -Ax -t x1 %t-filled | FileCheck --match-full-lines %s
 # CHECK: 000000 aa bb cc dd e9 e9 e9 e9 11 22 33 44
 
 --- !ELF
 FileHeader:
-  Class:           ELFCLASS32
+  Class:           ELFCLASS64
   Data:            ELFDATA2LSB
   Type:            ET_EXEC
-  Machine:         EM_HEXAGON
+  Machine:         EM_X86_64
 Sections:
   - Name:            .bss
     Type:            SHT_NOBITS
@@ -31,4 +34,3 @@ Sections:
     AddressAlign:    0x0001
     Content:         'AABBCCDD'
 ...
-
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
index 4edeb3905060541..5778a27d4bcaf0c 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -1,39 +1,32 @@
-# RUN: yaml2obj %s > %t
+# RUN: yaml2obj %s -o %t
 
-## Verify section headers before we perform several testings.
-# RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=ORG-SHDR
-# ORG-SHDR: Section Headers:
-# ORG-SHDR:  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
-# ORG-SHDR:  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
-# ORG-SHDR:  [ 1] .nogap            PROGBITS        0000000000000102 000042 000006 00   A  0   0  1
-# ORG-SHDR:  [ 2] .gap1             PROGBITS        0000000000000108 000048 000007 00  AX  0   0  1
-# ORG-SHDR:  [ 3] .gap2             PROGBITS        0000000000000110 000050 000004 00   A  0   0  1
-# ORG-SHDR:  [ 4] .nobit_tbss       NOBITS          0000000000000180 000058 000018 00 WAT  0   0  8
-# ORG-SHDR:  [ 5] .foo              PROGBITS        0000000000000184 00005c 000004 00  WA  0   0  1
-# ORG-SHDR:  [ 6] .nobit_bss        NOBITS          000000000000018a 000060 000008 00  WA  0   0  1
+## This test is partially based on one from D67689.
 
 # RUN: not llvm-objcopy --gap-fill 1 %t 2>&1 | FileCheck %s --check-prefix=NOT-BINARY
 # NOT-BINARY: error: '--gap-fill' is only supported for binary output
 
 # RUN: not llvm-objcopy -O binary --gap-fill %t 2>&1 | FileCheck %s --check-prefix=EMPTY
-# EMPTY: no input file specified
+# EMPTY: error: no input file specified
 
 # RUN: not llvm-objcopy -O binary --gap-fill= %t 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
-# BAD-FORMAT: bad number for --gap-fill:
+# BAD-FORMAT: error: --gap-fill: bad number:
 
 # RUN: not llvm-objcopy -O binary --gap-fill=x %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT
-# BAD-INPUT: bad number for --gap-fill: x
+# BAD-INPUT: error: --gap-fill: bad number: x
 
 # RUN: not llvm-objcopy -O binary --gap-fill=0x1G %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT2
-# BAD-INPUT2: bad number for --gap-fill: 0x1G
+# BAD-INPUT2: error: --gap-fill: bad number: 0x1G
 
-# RUN: not llvm-objcopy -O binary --gap-fill=0x1122 %t %t-val16 2>&1 | FileCheck %s --check-prefix=BAD-INPUT3
-# BAD-INPUT3: bad number for --gap-fill: 0x1122
+# RUN: not llvm-objcopy -O binary --gap-fill=ff %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT3
+# BAD-INPUT3: error: --gap-fill: bad number: ff
 
-# Test no gap fill gap fill with all allocatable output sections
+# RUN: llvm-objcopy -O binary --gap-fill=0x1122 %t %t-val16 2>&1 | FileCheck %s --check-prefix=TRUNCATED
+# TRUNCATED: warning: truncating gap-fill from 0x1122 to 0x22
+
+## Test no gap fill with all allocatable output sections.
 # RUN: llvm-objcopy -O binary %t %t-default
-# RUN: od -v -Ax -t x1 %t-default | FileCheck %s --check-prefix=DEFAULT
-# DEFAULT: 000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba 00 a1 b2
+# RUN: od -v -Ax -t x1 %t-default | FileCheck %s --check-prefix=DEFAULT --match-full-lines
+# DEFAULT:      000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba 00 a1 b2
 # DEFAULT-NEXT: 000010 c3 d4 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 # DEFAULT-NEXT: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 # DEFAULT-NEXT: 000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@@ -44,10 +37,10 @@
 # DEFAULT-NEXT: 000080 00 00 89 ab cd ef
 # DEFAULT-NEXT: 000086
 
-# Test gap fill with all allocatable output sections
+## Test gap fill with all allocatable output sections
 # RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled
-# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=FULL
-# FULL: 000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 a1 b2
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=FULL --match-full-lines
+# FULL:      000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 a1 b2
 # FULL-NEXT: 000010 c3 d4 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
 # FULL-NEXT: 000020 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
 # FULL-NEXT: 000030 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
@@ -58,17 +51,31 @@
 # FULL-NEXT: 000080 e9 e9 89 ab cd ef
 # FULL-NEXT: 000086
 
-# Test gap fill with the last section removed, should be truncated
+## Test gap fill with a decimal value.
+# RUN: llvm-objcopy -O binary --gap-fill=99 %t %t-filled-decimal
+# RUN: od -v -Ax -t x1 %t-filled-decimal | FileCheck %s --check-prefix=DEC --match-full-lines
+# DEC:      000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba 63 a1 b2
+# DEC-NEXT: 000010 c3 d4 63 63 63 63 63 63 63 63 63 63 63 63 63 63
+# DEC-NEXT: 000020 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
+# DEC-NEXT: 000030 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
+# DEC-NEXT: 000040 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
+# DEC-NEXT: 000050 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
+# DEC-NEXT: 000060 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
+# DEC-NEXT: 000070 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
+# DEC-NEXT: 000080 63 63 89 ab cd ef
+# DEC-NEXT: 000086
+
+## Test gap fill with the last section removed, should be truncated.
 # RUN: llvm-objcopy -O binary --gap-fill=0xe9 --remove-section=.foo %t %t-filled
-# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-LAST-SECTION
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-LAST-SECTION --match-full-lines
 # REMOVE-LAST-SECTION: 000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 a1 b2
 # REMOVE-LAST-SECTION-NEXT: 000010 c3 d4
 # REMOVE-LAST-SECTION-NEXT: 000012
 
-# Test gap fill with the middle section removed, should be filled
+## Test gap fill with the middle section removed, should be filled.
 # RUN: llvm-objcopy -O binary --gap-fill=0xe9 --remove-section=.gap2 %t %t-filled
-# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-MIDDLE-SECTION
-# REMOVE-MIDDLE-SECTION: 000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 e9 e9
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-MIDDLE-SECTION --match-full-lines
+# REMOVE-MIDDLE-SECTION:      000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 e9 e9
 # REMOVE-MIDDLE-SECTION-NEXT: 000010 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
 # REMOVE-MIDDLE-SECTION-NEXT: 000020 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
 # REMOVE-MIDDLE-SECTION-NEXT: 000030 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
@@ -123,7 +130,7 @@ Sections:
     Address:         0x0180
     AddressAlign:    0x0008
     Size:            0x0018
-  - Name:            .space4             # in the different segment
+  - Name:            .space4
     Type:            Fill
     Pattern:         '01234567'
     Size:            0x4
@@ -145,5 +152,4 @@ Sections:
     AddressAlign:    0x0001
     EntSize:         0x0001
     Content:         4743433A
-
 ...
diff --git a/llvm/test/tools/llvm-objcopy/ELF/pad-to.test b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
index fb777ad750dbfe0..99f28b5d4b6ef70 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
@@ -1,24 +1,27 @@
-# RUN: yaml2obj %s > %t
-
-# baseline, no padding
-# RUN: llvm-objcopy -O binary %t %t.bin
+# RUN: yaml2obj %s -o %t
 
 # RUN: not llvm-objcopy --pad-to=1 %t 2>&1 | FileCheck %s --check-prefix=NOT-BINARY
 # NOT-BINARY: error: '--pad-to' is only supported for binary output
 
 # RUN: not llvm-objcopy -O binary --pad-to= %t 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
-# BAD-FORMAT: bad address for --pad-to:
+# BAD-FORMAT: error: --pad-to: bad number:
 
 # RUN: not llvm-objcopy -O binary --pad-to=x %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT
-# BAD-INPUT: bad address for --pad-to: x
+# BAD-INPUT: error: --pad-to: bad number: x
 
 # RUN: not llvm-objcopy -O binary --pad-to=0x1G %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT2
-# BAD-INPUT2: bad address for --pad-to: 0x1G
+# BAD-INPUT2: error: --pad-to: bad number: 0x1G
+
+# RUN: not llvm-objcopy -O binary --pad-to=ff %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT3
+# BAD-INPUT3: error: --pad-to: bad number: ff
 
 # RUN: not llvm-objcopy -O binary --pad-to=0x112233445566778899 %t 2>&1 | FileCheck %s --check-prefix=BAD-NUMBER
-# BAD-NUMBER: bad address for --pad-to: 0x112233445566778899
+# BAD-NUMBER: error: --pad-to: bad number: 0x112233445566778899
 
-# Pad to a address smaller than the binary size
+## Save the baseline, not padded output.
+# RUN: llvm-objcopy -O binary %t %t.bin
+
+## Pad to a address smaller than the binary size.
 # RUN: llvm-objcopy -O binary --pad-to=0x20 %t %t-p1
 # RUN: cmp %t.bin %t-p1
 # RUN: llvm-objcopy -O binary --pad-to=0x200 %t %t-p2
@@ -26,21 +29,28 @@
 
 ## Pad all allocatable sections to a valid address.
 # RUN: llvm-objcopy -O binary --pad-to=0x218 %t %t-pad-default
-# RUN: od -v -Ax -t x1 %t-pad-default | FileCheck %s --check-prefix=DEFAULT
-# DEFAULT: 000000 11 22 33 44 55 66 00 00 00 00 00 00 00 00 00 00
+# RUN: od -v -Ax -t x1 %t-pad-default | FileCheck %s --check-prefix=DEFAULT --match-full-lines
+# DEFAULT:      000000 11 22 33 44 55 66 00 00 00 00 00 00 00 00 00 00
 # DEFAULT-NEXT: 000010 77 88 99 aa 00 00 00 00
 # DEFAULT-NEXT: 000018
 
+## Use a decimal number of padding address, verify it's not misunderstood.
+# RUN: llvm-objcopy -O binary --pad-to=536 %t %t-pad-decimal
+# RUN: od -v -Ax -t x1 %t-pad-decimal | FileCheck %s --check-prefix=DECIMAL --match-full-lines
+# DECIMAL:      000000 11 22 33 44 55 66 00 00 00 00 00 00 00 00 00 00
+# DECIMAL-NEXT: 000010 77 88 99 aa 00 00 00 00
+# DECIMAL-NEXT: 000018
+
 ## Pad all allocatable sections to a valid address, using --gap-fill.
 # RUN: llvm-objcopy -O binary --pad-to=0x218 --gap-fill=0xe9 %t %t-pad-fill
-# RUN: od -v -Ax -t x1 %t-pad-fill | FileCheck %s --check-prefix=FILL
-# FILL: 000000 11 22 33 44 55 66 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
+# RUN: od -v -Ax -t x1 %t-pad-fill | FileCheck %s --check-prefix=FILL --match-full-lines
+# FILL:      000000 11 22 33 44 55 66 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
 # FILL-NEXT: 000010 77 88 99 aa e9 e9 e9 e9
 # FILL-NEXT: 000018
 
-# Test gap fill with a section removed
+## Test gap fill with a section removed.
 # RUN: llvm-objcopy -O binary --pad-to=0x218 --gap-fill=0xe9 --remove-section=.section2 %t %t-filled
-# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-SECTION
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-SECTION --match-full-lines
 # REMOVE-SECTION: 000000 11 22 33 44 55 66 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
 # REMOVE-SECTION-NEXT: 000010 e9 e9 e9 e9 e9 e9 e9 e9
 # REMOVE-SECTION-NEXT: 000018
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index b4104053e2b3f91..4cd9a1545802442 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -743,11 +743,16 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
       return createStringError(
           errc::invalid_argument,
           "'--gap-fill' is only supported for binary output");
-    ErrorOr<uint8_t> Val = getAsInteger<uint8_t>(A->getValue());
+    ErrorOr<uint64_t> Val = getAsInteger<uint64_t>(A->getValue());
     if (!Val)
-      return createStringError(Val.getError(), "bad number for --gap-fill: %s",
+      return createStringError(Val.getError(), "--gap-fill: bad number: %s",
                                A->getValue());
-    Config.GapFill = Val.get();
+    uint8_t ByteVal = Val.get();
+    if (ByteVal != Val.get())
+      llvm::errs() << "warning: truncating gap-fill from 0x"
+                   << llvm::utohexstr(Val.get(), true) << " to 0x"
+                   << llvm::utohexstr(ByteVal, true) << '\n';
+    Config.GapFill = ByteVal;
   } else
     Config.GapFill = 0; // The value of zero is equivalent to no fill.
 
@@ -758,10 +763,11 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
           "'--pad-to' is only supported for binary output");
     ErrorOr<uint64_t> Addr = getAsInteger<uint64_t>(A->getValue());
     if (!Addr)
-      return createStringError(Addr.getError(), "bad address for --pad-to: %s",
+      return createStringError(Addr.getError(), "--pad-to: bad number: %s",
                                A->getValue());
     Config.PadTo = *Addr;
-  }
+  } else
+    Config.PadTo = 0;
 
   for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
     if (!StringRef(Arg->getValue()).contains('='))

>From 29ff70e5e28cad72951696fa614c258e0fa471d8 Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Wed, 4 Oct 2023 08:53:20 -0700
Subject: [PATCH 3/6] Addressing more feedback.

Change-Id: Ic56f43f2ef4818381d98a062d1764ec127ea646e
---
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            |  4 +-
 llvm/lib/ObjCopy/ELF/ELFObject.h              |  2 +-
 .../llvm-objcopy/ELF/gap-fill-order.test      | 36 ---------
 .../test/tools/llvm-objcopy/ELF/gap-fill.test | 75 +++++++++++++++----
 llvm/test/tools/llvm-objcopy/ELF/pad-to.test  |  2 +-
 5 files changed, 63 insertions(+), 56 deletions(-)
 delete mode 100644 llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test

diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 85a123d26ebfe42..07128ca45a85090 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2651,7 +2651,7 @@ Error BinaryWriter::write() {
 
   assert(LoadableSections.front()->Offset == 0);
 
-  for (std::size_t i = 0; i != LoadableSections.size(); ++i) {
+  for (size_t i = 0; i != LoadableSections.size(); ++i) {
     const SectionBase &Sec = *LoadableSections[i];
     if (Error Err = Sec.accept(*SecWriter))
       return Err;
@@ -2690,7 +2690,7 @@ Error BinaryWriter::finalize() {
   // file size. This might not be the same as the offset returned by
   // layoutSections, because we want to truncate the last segment to the end of
   // its last non-empty section, to match GNU objcopy's behaviour.
-  TotalSize = PadTo.value() > MinAddr ? PadTo.value() - MinAddr : 0;
+  TotalSize = PadTo > MinAddr ? PadTo - MinAddr : 0;
   for (SectionBase &Sec : Obj.allocSections())
     if (Sec.Type != SHT_NOBITS && Sec.Size > 0) {
       Sec.Offset = Sec.Addr - MinAddr;
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index bf6fa32908e3dcf..95bea0964eaef38 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -358,7 +358,7 @@ template <class ELFT> class ELFWriter : public Writer {
 class BinaryWriter : public Writer {
 private:
   const uint8_t GapFill;
-  const std::optional<uint64_t> PadTo;
+  const uint64_t PadTo;
   std::unique_ptr<BinarySectionWriter> SecWriter;
 
   uint64_t TotalSize = 0;
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test
deleted file mode 100644
index c154617bd3cd317..000000000000000
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill-order.test
+++ /dev/null
@@ -1,36 +0,0 @@
-# RUN: yaml2obj %s -o %t
-
-## In this test, output sections are defined out of
-## order in respect to their load addresses. Verify
-## that gaps are still correctly filled.
-
-# RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled
-# RUN: od -v -Ax -t x1 %t-filled | FileCheck --match-full-lines %s
-# CHECK: 000000 aa bb cc dd e9 e9 e9 e9 11 22 33 44
-
---- !ELF
-FileHeader:
-  Class:           ELFCLASS64
-  Data:            ELFDATA2LSB
-  Type:            ET_EXEC
-  Machine:         EM_X86_64
-Sections:
-  - Name:            .bss
-    Type:            SHT_NOBITS
-    Flags:           [ SHF_ALLOC, SHF_WRITE ]
-    Address:         0x0104
-    AddressAlign:    0x0001
-    Size:            4
-  - Name:            .section1
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_WRITE ]
-    Address:         0x0108
-    AddressAlign:    0x0001
-    Content:         '11223344'
-  - Name:            .section3
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_WRITE ]
-    Address:         0x0100
-    AddressAlign:    0x0001
-    Content:         'AABBCCDD'
-...
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
index 5778a27d4bcaf0c..9d2b172096647f6 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -1,27 +1,37 @@
-# RUN: yaml2obj %s -o %t
-
-## This test is partially based on one from D67689.
+# RUN: yaml2obj --docnum=1 %s -o %t
 
 # RUN: not llvm-objcopy --gap-fill 1 %t 2>&1 | FileCheck %s --check-prefix=NOT-BINARY
 # NOT-BINARY: error: '--gap-fill' is only supported for binary output
 
-# RUN: not llvm-objcopy -O binary --gap-fill %t 2>&1 | FileCheck %s --check-prefix=EMPTY
-# EMPTY: error: no input file specified
-
-# RUN: not llvm-objcopy -O binary --gap-fill= %t 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
+# RUN: not llvm-objcopy -O binary --gap-fill= %t %t.bin 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
 # BAD-FORMAT: error: --gap-fill: bad number:
 
-# RUN: not llvm-objcopy -O binary --gap-fill=x %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT
+# RUN: not llvm-objcopy -O binary --gap-fill=x %t %t.bin 2>&1 | FileCheck %s --check-prefix=BAD-INPUT
 # BAD-INPUT: error: --gap-fill: bad number: x
 
-# RUN: not llvm-objcopy -O binary --gap-fill=0x1G %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT2
-# BAD-INPUT2: error: --gap-fill: bad number: 0x1G
+# RUN: not llvm-objcopy -O binary --gap-fill=0x %t %t.bin 2>&1 | FileCheck %s --check-prefix=BAD-INPUT2
+# BAD-INPUT2: error: --gap-fill: bad number: 0x
+
+# RUN: not llvm-objcopy -O binary --gap-fill=0x1G %t %t.bin 2>&1 | FileCheck %s --check-prefix=BAD-INPUT3
+# BAD-INPUT3: error: --gap-fill: bad number: 0x1G
 
-# RUN: not llvm-objcopy -O binary --gap-fill=ff %t 2>&1 | FileCheck %s --check-prefix=BAD-INPUT3
-# BAD-INPUT3: error: --gap-fill: bad number: ff
+# RUN: not llvm-objcopy -O binary --gap-fill=ff %t %t.bin 2>&1 | FileCheck %s --check-prefix=BAD-INPUT4
+# BAD-INPUT4: error: --gap-fill: bad number: ff
 
-# RUN: llvm-objcopy -O binary --gap-fill=0x1122 %t %t-val16 2>&1 | FileCheck %s --check-prefix=TRUNCATED
-# TRUNCATED: warning: truncating gap-fill from 0x1122 to 0x22
+# RUN: llvm-objcopy -O binary --gap-fill=0x1122 %t %t-val16 2>&1 | FileCheck %s --check-prefix=TRUNCATED-ERR
+# TRUNCATED-ERR: warning: truncating gap-fill from 0x1122 to 0x22
+
+# RUN: od -v -Ax -t x1 %t-val16 | FileCheck %s --check-prefix=TRUNCATED --match-full-lines
+# TRUNCATED:      000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba 22 a1 b2
+# TRUNCATED-NEXT: 000010 c3 d4 22 22 22 22 22 22 22 22 22 22 22 22 22 22
+# TRUNCATED-NEXT: 000020 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
+# TRUNCATED-NEXT: 000030 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
+# TRUNCATED-NEXT: 000040 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
+# TRUNCATED-NEXT: 000050 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
+# TRUNCATED-NEXT: 000060 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
+# TRUNCATED-NEXT: 000070 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
+# TRUNCATED-NEXT: 000080 22 22 89 ab cd ef
+# TRUNCATED-NEXT: 000086
 
 ## Test no gap fill with all allocatable output sections.
 # RUN: llvm-objcopy -O binary %t %t-default
@@ -37,7 +47,7 @@
 # DEFAULT-NEXT: 000080 00 00 89 ab cd ef
 # DEFAULT-NEXT: 000086
 
-## Test gap fill with all allocatable output sections
+## Test gap fill with all allocatable output sections.
 # RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled
 # RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=FULL --match-full-lines
 # FULL:      000000 ee ff 11 22 33 44 aa bb cc dd fe dc ba e9 a1 b2
@@ -152,4 +162,37 @@ Sections:
     AddressAlign:    0x0001
     EntSize:         0x0001
     Content:         4743433A
-...
+
+## In this test, output sections are defined out of in respect to their load
+## addresses. Verify that gaps are still correctly filled.
+
+# RUN: yaml2obj --docnum=2 %s -o %t
+# RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled
+# RUN: od -v -Ax -t x1 %t-filled | FileCheck --match-full-lines %s
+# CHECK: 000000 aa bb cc dd e9 e9 e9 e9 11 22 33 44
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x0104
+    AddressAlign:    0x0001
+    Size:            4
+  - Name:            .section1
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x0108
+    AddressAlign:    0x0001
+    Content:         '11223344'
+  - Name:            .section3
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x0100
+    AddressAlign:    0x0001
+    Content:         'AABBCCDD'
diff --git a/llvm/test/tools/llvm-objcopy/ELF/pad-to.test b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
index 99f28b5d4b6ef70..eedbe51c9f51ee7 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
@@ -21,7 +21,7 @@
 ## Save the baseline, not padded output.
 # RUN: llvm-objcopy -O binary %t %t.bin
 
-## Pad to a address smaller than the binary size.
+## Pad to an address smaller than the binary size.
 # RUN: llvm-objcopy -O binary --pad-to=0x20 %t %t-p1
 # RUN: cmp %t.bin %t-p1
 # RUN: llvm-objcopy -O binary --pad-to=0x200 %t %t-p2

>From 3452fc8278a9afdafee8bdc19898be434cb13ed3 Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Mon, 30 Oct 2023 11:35:50 -0700
Subject: [PATCH 4/6] Another round of review fixes.

Use reportWarning(), some renaming and rewording and other miscellaneous
changes.
---
 llvm/include/llvm/ObjCopy/ObjCopy.h          |  3 +++
 llvm/lib/ObjCopy/ELF/ELFObject.cpp           | 18 +++++++++---------
 llvm/test/tools/llvm-objcopy/ELF/pad-to.test |  4 ++--
 llvm/tools/llvm-objcopy/ObjcopyOptions.cpp   | 14 +++++++-------
 llvm/tools/llvm-objcopy/llvm-objcopy.cpp     |  8 +++++++-
 5 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/llvm/include/llvm/ObjCopy/ObjCopy.h b/llvm/include/llvm/ObjCopy/ObjCopy.h
index 023814002c72710..4d4c02685dee725 100644
--- a/llvm/include/llvm/ObjCopy/ObjCopy.h
+++ b/llvm/include/llvm/ObjCopy/ObjCopy.h
@@ -36,6 +36,9 @@ Error executeObjcopyOnArchive(const MultiFormatConfig &Config,
 Error executeObjcopyOnBinary(const MultiFormatConfig &Config,
                              object::Binary &In, raw_ostream &Out);
 
+/// Print a warning using the content of the error \p E.
+ErrorSuccess reportWarning(Error E);
+
 } // end namespace objcopy
 } // end namespace llvm
 
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 0e90c608b0d6638..7f3802e666b9e2b 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2635,30 +2635,30 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
 }
 
 Error BinaryWriter::write() {
-  SmallVector<const SectionBase *, 30> LoadableSections;
+  SmallVector<const SectionBase *, 30> BitsSections;
   for (const SectionBase &Sec : Obj.allocSections()) {
     if (Sec.Type != SHT_NOBITS)
-      LoadableSections.push_back(&Sec);
+      BitsSections.push_back(&Sec);
   }
 
-  if (LoadableSections.empty())
+  if (BitsSections.empty())
     return Error::success();
 
-  llvm::stable_sort(LoadableSections,
+  llvm::stable_sort(BitsSections,
                     [](const SectionBase *LHS, const SectionBase *RHS) {
                       return LHS->Offset < RHS->Offset;
                     });
 
-  assert(LoadableSections.front()->Offset == 0);
+  assert(BitsSections.front()->Offset == 0);
 
-  for (size_t i = 0; i != LoadableSections.size(); ++i) {
-    const SectionBase &Sec = *LoadableSections[i];
+  for (size_t i = 0; i != BitsSections.size(); ++i) {
+    const SectionBase &Sec = *BitsSections[i];
     if (Error Err = Sec.accept(*SecWriter))
       return Err;
     if (GapFill == 0)
       continue;
-    uint64_t PadOffset = (i < LoadableSections.size() - 1)
-                             ? LoadableSections[i + 1]->Offset
+    uint64_t PadOffset = (i < BitsSections.size() - 1)
+                             ? BitsSections[i + 1]->Offset
                              : Buf->getBufferSize();
     assert(PadOffset <= Buf->getBufferSize());
     assert(Sec.Offset + Sec.Size <= PadOffset);
diff --git a/llvm/test/tools/llvm-objcopy/ELF/pad-to.test b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
index eedbe51c9f51ee7..0da0fd71c745c26 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
@@ -34,7 +34,7 @@
 # DEFAULT-NEXT: 000010 77 88 99 aa 00 00 00 00
 # DEFAULT-NEXT: 000018
 
-## Use a decimal number of padding address, verify it's not misunderstood.
+## Use a decimal number for the padding address and verify it is not misunderstood.
 # RUN: llvm-objcopy -O binary --pad-to=536 %t %t-pad-decimal
 # RUN: od -v -Ax -t x1 %t-pad-decimal | FileCheck %s --check-prefix=DECIMAL --match-full-lines
 # DECIMAL:      000000 11 22 33 44 55 66 00 00 00 00 00 00 00 00 00 00
@@ -48,7 +48,7 @@
 # FILL-NEXT: 000010 77 88 99 aa e9 e9 e9 e9
 # FILL-NEXT: 000018
 
-## Test gap fill with a section removed.
+## Remove the last section containing data and test that the padded space is gap filled.
 # RUN: llvm-objcopy -O binary --pad-to=0x218 --gap-fill=0xe9 --remove-section=.section2 %t %t-filled
 # RUN: od -v -Ax -t x1 %t-filled | FileCheck %s --check-prefix=REMOVE-SECTION --match-full-lines
 # REMOVE-SECTION: 000000 11 22 33 44 55 66 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 4cd9a1545802442..726ac73481ebf49 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -15,6 +15,7 @@
 #include "llvm/ObjCopy/CommonConfig.h"
 #include "llvm/ObjCopy/ConfigManager.h"
 #include "llvm/ObjCopy/MachO/MachOConfig.h"
+#include "llvm/ObjCopy/ObjCopy.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/CRC.h"
@@ -749,12 +750,12 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
                                A->getValue());
     uint8_t ByteVal = Val.get();
     if (ByteVal != Val.get())
-      llvm::errs() << "warning: truncating gap-fill from 0x"
-                   << llvm::utohexstr(Val.get(), true) << " to 0x"
-                   << llvm::utohexstr(ByteVal, true) << '\n';
+      if (Error E = reportWarning(llvm::createStringError(
+              std::errc::value_too_large,
+              "truncating gap-fill from 0x%x to 0x%x", Val.get(), ByteVal)))
+        return std::move(E);
     Config.GapFill = ByteVal;
-  } else
-    Config.GapFill = 0; // The value of zero is equivalent to no fill.
+  }
 
   if (const auto *A = InputArgs.getLastArg(OBJCOPY_pad_to)) {
     if (Config.OutputFormat != FileFormat::Binary)
@@ -766,8 +767,7 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
       return createStringError(Addr.getError(), "--pad-to: bad number: %s",
                                A->getValue());
     Config.PadTo = *Addr;
-  } else
-    Config.PadTo = 0;
+  }
 
   for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
     if (!StringRef(Arg->getValue()).contains('='))
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index 2afa97601f5cfd8..60e6e61aae1be3a 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -67,12 +67,18 @@ using namespace llvm::object;
 // The name this program was invoked as.
 static StringRef ToolName;
 
-static ErrorSuccess reportWarning(Error E) {
+namespace llvm {
+namespace objcopy {
+
+ErrorSuccess reportWarning(Error E) {
   assert(E);
   WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n';
   return Error::success();
 }
 
+} // namespace objcopy
+} // namespace llvm
+
 static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {
   StringRef Stem = sys::path::stem(ToolName);
   auto Is = [=](StringRef Tool) {

>From 6ba8666ac7cbf0329d26a002af84036f02d3d5bf Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Mon, 30 Oct 2023 12:34:29 -0700
Subject: [PATCH 5/6] Fill a missing word in a test comment.

---
 llvm/test/tools/llvm-objcopy/ELF/gap-fill.test | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
index 9d2b172096647f6..5b347d7be79a68e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -163,8 +163,8 @@ Sections:
     EntSize:         0x0001
     Content:         4743433A
 
-## In this test, output sections are defined out of in respect to their load
-## addresses. Verify that gaps are still correctly filled.
+## In this test, output sections are defined out of order in respect to their
+## load addresses. Verify that gaps are still correctly filled.
 
 # RUN: yaml2obj --docnum=2 %s -o %t
 # RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled

>From 8c689d2e3e40fdd792bdf5e13edba091a83cb064 Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Tue, 31 Oct 2023 08:16:35 -0700
Subject: [PATCH 6/6] Some more aesthetics.

---
 llvm/lib/ObjCopy/ELF/ELFObject.cpp             | 18 +++++++++---------
 llvm/test/tools/llvm-objcopy/ELF/gap-fill.test |  2 +-
 llvm/tools/llvm-objcopy/llvm-objcopy.cpp       |  8 +-------
 3 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index b3131df156b7ef6..5352736bdcb9b80 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2636,30 +2636,30 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
 }
 
 Error BinaryWriter::write() {
-  SmallVector<const SectionBase *, 30> BitsSections;
+  SmallVector<const SectionBase *, 30> SectionsToWrite;
   for (const SectionBase &Sec : Obj.allocSections()) {
     if (Sec.Type != SHT_NOBITS)
-      BitsSections.push_back(&Sec);
+      SectionsToWrite.push_back(&Sec);
   }
 
-  if (BitsSections.empty())
+  if (SectionsToWrite.empty())
     return Error::success();
 
-  llvm::stable_sort(BitsSections,
+  llvm::stable_sort(SectionsToWrite,
                     [](const SectionBase *LHS, const SectionBase *RHS) {
                       return LHS->Offset < RHS->Offset;
                     });
 
-  assert(BitsSections.front()->Offset == 0);
+  assert(SectionsToWrite.front()->Offset == 0);
 
-  for (size_t i = 0; i != BitsSections.size(); ++i) {
-    const SectionBase &Sec = *BitsSections[i];
+  for (size_t i = 0; i != SectionsToWrite.size(); ++i) {
+    const SectionBase &Sec = *SectionsToWrite[i];
     if (Error Err = Sec.accept(*SecWriter))
       return Err;
     if (GapFill == 0)
       continue;
-    uint64_t PadOffset = (i < BitsSections.size() - 1)
-                             ? BitsSections[i + 1]->Offset
+    uint64_t PadOffset = (i < SectionsToWrite.size() - 1)
+                             ? SectionsToWrite[i + 1]->Offset
                              : Buf->getBufferSize();
     assert(PadOffset <= Buf->getBufferSize());
     assert(Sec.Offset + Sec.Size <= PadOffset);
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
index 5b347d7be79a68e..e2f467e988d3d8d 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -163,7 +163,7 @@ Sections:
     EntSize:         0x0001
     Content:         4743433A
 
-## In this test, output sections are defined out of order in respect to their
+## In this test, output sections are defined out of order with respect to their
 ## load addresses. Verify that gaps are still correctly filled.
 
 # RUN: yaml2obj --docnum=2 %s -o %t
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index 60e6e61aae1be3a..434fd7df0464ed9 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -67,18 +67,12 @@ using namespace llvm::object;
 // The name this program was invoked as.
 static StringRef ToolName;
 
-namespace llvm {
-namespace objcopy {
-
-ErrorSuccess reportWarning(Error E) {
+ErrorSuccess llvm::objcopy::reportWarning(Error E) {
   assert(E);
   WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n';
   return Error::success();
 }
 
-} // namespace objcopy
-} // namespace llvm
-
 static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {
   StringRef Stem = sys::path::stem(ToolName);
   auto Is = [=](StringRef Tool) {



More information about the cfe-commits mailing list