[clang] [llvm] [clang-tools-extra] [llvm-objcopy] Add --gap-fill and --pad-to options (PR #65815)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 12 11:19:03 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 01/10] [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 0233a4f7b2f045..6e13cd94b92fda 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 e7ce1e6f2c54d7..ebfd404293400e 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 58cb9cb65679b7..37d2af2139e317 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 697afab2a617b4..77092368883272 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 89a03b3fe0ee35..bf6fa32908e3dc 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 00000000000000..4b0ecad5cd3bfa
--- /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 00000000000000..4edeb390506054
--- /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 00000000000000..fb777ad750dbfe
--- /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 d33adb0b6a3e47..b4104053e2b3f9 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 ea8828637222ac..556f84e3154fe0 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 02/10] 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 226ee606d17ee2..bad5dbc8a10247 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 ebfd404293400e..386c20aec184de 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 5b8e2f5dc2003a..6074723279e815 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 77092368883272..85a123d26ebfe4 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 4b0ecad5cd3bfa..c154617bd3cd31 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 4edeb390506054..5778a27d4bcaf0 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 fb777ad750dbfe..99f28b5d4b6ef7 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 b4104053e2b3f9..4cd9a154580244 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 03/10] 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 85a123d26ebfe4..07128ca45a8509 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 bf6fa32908e3dc..95bea0964eaef3 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 c154617bd3cd31..00000000000000
--- 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 5778a27d4bcaf0..9d2b172096647f 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 99f28b5d4b6ef7..eedbe51c9f51ee 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 04/10] 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 023814002c7271..4d4c02685dee72 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 0e90c608b0d663..7f3802e666b9e2 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 eedbe51c9f51ee..0da0fd71c745c2 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 4cd9a154580244..726ac73481ebf4 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 2afa97601f5cfd..60e6e61aae1be3 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 05/10] 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 9d2b172096647f..5b347d7be79a68 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 06/10] 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 b3131df156b7ef..5352736bdcb9b8 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 5b347d7be79a68..e2f467e988d3d8 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 60e6e61aae1be3..434fd7df0464ed 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) {
>From 7670531cb21f0c3eeb3492106df72d7f7d2d6ae4 Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Mon, 11 Dec 2023 10:45:10 -0800
Subject: [PATCH 07/10] Lastest review.
Change-Id: I3c2b19888c9e4d397a191861136c48b5715155c6
---
llvm/test/tools/llvm-objcopy/ELF/gap-fill.test | 13 +++++--------
llvm/test/tools/llvm-objcopy/ELF/pad-to.test | 4 ----
llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 7 +++----
llvm/tools/llvm-objcopy/ObjcopyOpts.td | 8 ++++----
4 files changed, 12 insertions(+), 20 deletions(-)
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
index e2f467e988d3d8..396e0220619f71 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -18,8 +18,8 @@
# 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-ERR
-# TRUNCATED-ERR: warning: truncating gap-fill from 0x1122 to 0x22
+# RUN: not llvm-objcopy -O binary --gap-fill=0x1122 %t %t-val16 2>&1 | FileCheck %s --check-prefix=TRUNCATED-ERR
+# TRUNCATED-ERR: error: gap-fill value 0x1122 is out of range (0 to 0xff)
# 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
@@ -166,9 +166,9 @@ Sections:
## 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
-# RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t %t-filled
-# RUN: od -v -Ax -t x1 %t-filled | FileCheck --match-full-lines %s
+# RUN: yaml2obj --docnum=2 %s -o %t.2
+# RUN: llvm-objcopy -O binary --gap-fill=0xe9 %t.2 %t.2.filled
+# RUN: od -v -Ax -t x1 %t.2.filled | FileCheck --match-full-lines %s
# CHECK: 000000 aa bb cc dd e9 e9 e9 e9 11 22 33 44
--- !ELF
@@ -182,17 +182,14 @@ Sections:
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 0da0fd71c745c2..eb3608860a5433 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
@@ -66,7 +66,6 @@ Sections:
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Address: 0x0200
- AddressAlign: 0x0001
Size: 0x6
Content: '112233445566'
- Name: .space
@@ -77,18 +76,15 @@ Sections:
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 e9669ef9260a48..bc7b754e7cecf0 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -749,10 +749,9 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
A->getValue());
uint8_t ByteVal = Val.get();
if (ByteVal != Val.get())
- 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);
+ return createStringError(
+ std::errc::value_too_large,
+ "gap-fill value %s is out of range (0 to 0xff)", A->getValue());
Config.GapFill = ByteVal;
}
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index 556f84e3154fe0..a5363f4e0c3f01 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -234,11 +234,11 @@ defm update_section
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.">,
+ "This option is only supported for the ELF input and binary output">,
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.">,
+ : Eq<"pad-to", "Pad the output up to the load address <address>, using a value "
+ "of zero or the value specified by the --gap-fill option. "
+ "This option is only supported for the ELF input and binary output">,
MetaVarName<"address">;
>From 3fd26d90babfb76b2d66d1a3c3e4d39c8527d502 Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Mon, 11 Dec 2023 10:50:21 -0800
Subject: [PATCH 08/10] Format.
Change-Id: I44945026180d959b9616d70b910321cfc8476eff
---
llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index bc7b754e7cecf0..aa22397f310f49 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -749,9 +749,9 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
A->getValue());
uint8_t ByteVal = Val.get();
if (ByteVal != Val.get())
- return createStringError(
- std::errc::value_too_large,
- "gap-fill value %s is out of range (0 to 0xff)", A->getValue());
+ return createStringError(std::errc::value_too_large,
+ "gap-fill value %s is out of range (0 to 0xff)",
+ A->getValue());
Config.GapFill = ByteVal;
}
>From 9d5783cc9284ec3e1cb089e4c00eeeacf739788c Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Mon, 11 Dec 2023 11:03:54 -0800
Subject: [PATCH 09/10] Failing test fixed.
Change-Id: Icd803193dd02f63959b56a6f9e404c4751cc933b
---
llvm/test/tools/llvm-objcopy/ELF/gap-fill.test | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
index 396e0220619f71..d17cb9568cda3e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -21,18 +21,6 @@
# RUN: not llvm-objcopy -O binary --gap-fill=0x1122 %t %t-val16 2>&1 | FileCheck %s --check-prefix=TRUNCATED-ERR
# TRUNCATED-ERR: error: gap-fill value 0x1122 is out of range (0 to 0xff)
-# 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
# RUN: od -v -Ax -t x1 %t-default | FileCheck %s --check-prefix=DEFAULT --match-full-lines
>From 3f1cd7d62502d6c09fa7f6f6fa512c4cc87126c7 Mon Sep 17 00:00:00 2001
From: Alexey Karyakin <akaryaki at quicinc.com>
Date: Tue, 12 Dec 2023 11:06:41 -0800
Subject: [PATCH 10/10] Remove remaining AddressAlign from the test and undo
reportWarning.
---
llvm/include/llvm/ObjCopy/ObjCopy.h | 3 ---
llvm/test/tools/llvm-objcopy/ELF/gap-fill.test | 7 -------
llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 1 -
llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 2 +-
4 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/llvm/include/llvm/ObjCopy/ObjCopy.h b/llvm/include/llvm/ObjCopy/ObjCopy.h
index 4d4c02685dee72..023814002c7271 100644
--- a/llvm/include/llvm/ObjCopy/ObjCopy.h
+++ b/llvm/include/llvm/ObjCopy/ObjCopy.h
@@ -36,9 +36,6 @@ 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/test/tools/llvm-objcopy/ELF/gap-fill.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
index d17cb9568cda3e..fa6230e64bc77c 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -99,14 +99,12 @@ Sections:
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
@@ -116,7 +114,6 @@ Sections:
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Address: 0x0110
- AddressAlign: 0x0001
Content: 'A1B2C3D4'
- Name: .space3
Type: Fill
@@ -126,7 +123,6 @@ Sections:
Type: SHT_NOBITS
Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
Address: 0x0180
- AddressAlign: 0x0008
Size: 0x0018
- Name: .space4
Type: Fill
@@ -136,18 +132,15 @@ Sections:
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/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index aa22397f310f49..e1a3369a0aa2ac 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -14,7 +14,6 @@
#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"
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index 1fc8f64c6dfc7d..558359eca3cd72 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -66,7 +66,7 @@ using namespace llvm::object;
// The name this program was invoked as.
static StringRef ToolName;
-ErrorSuccess llvm::objcopy::reportWarning(Error E) {
+static ErrorSuccess reportWarning(Error E) {
assert(E);
WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n';
return Error::success();
More information about the cfe-commits
mailing list