[llvm] 4070dff - [llvm-objcopy] Add --gap-fill and --pad-to options (#65815)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 14 14:28:39 PST 2023
Author: quic-akaryaki
Date: 2023-12-14T16:28:34-06:00
New Revision: 4070dffd34e99915b005c655086d92e42c004d25
URL: https://github.com/llvm/llvm-project/commit/4070dffd34e99915b005c655086d92e42c004d25
DIFF: https://github.com/llvm/llvm-project/commit/4070dffd34e99915b005c655086d92e42c004d25.diff
LOG: [llvm-objcopy] Add --gap-fill and --pad-to options (#65815)
`--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 input and binary output.
Added:
llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
llvm/test/tools/llvm-objcopy/ELF/pad-to.test
Modified:
llvm/docs/CommandGuide/llvm-objcopy.rst
llvm/docs/ReleaseNotes.rst
llvm/include/llvm/ObjCopy/CommonConfig.h
llvm/lib/ObjCopy/ConfigManager.cpp
llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
llvm/lib/ObjCopy/ELF/ELFObject.cpp
llvm/lib/ObjCopy/ELF/ELFObject.h
llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
llvm/tools/llvm-objcopy/ObjcopyOpts.td
Removed:
################################################################################
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/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index d90b29f63d90b4..bef812b0b12096 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -270,6 +270,9 @@ Changes to the LLVM tools
* llvm-symbolizer and llvm-addr2line now support addresses specified as symbol names.
+* 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 e7ce1e6f2c54d7..386c20aec184de 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;
+ 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 bccb2903e62aeb..10ece49028f217 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.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/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index ceb676dec22f5a..daf03810fd7bff 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 0a54d3798d8bfc..5352736bdcb9b8 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2636,9 +2636,36 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
}
Error BinaryWriter::write() {
- for (const SectionBase &Sec : Obj.allocSections())
+ SmallVector<const SectionBase *, 30> SectionsToWrite;
+ for (const SectionBase &Sec : Obj.allocSections()) {
+ if (Sec.Type != SHT_NOBITS)
+ SectionsToWrite.push_back(&Sec);
+ }
+
+ if (SectionsToWrite.empty())
+ return Error::success();
+
+ llvm::stable_sort(SectionsToWrite,
+ [](const SectionBase *LHS, const SectionBase *RHS) {
+ return LHS->Offset < RHS->Offset;
+ });
+
+ assert(SectionsToWrite.front()->Offset == 0);
+
+ 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 < SectionsToWrite.size() - 1)
+ ? SectionsToWrite[i + 1]->Offset
+ : Buf->getBufferSize();
+ assert(PadOffset <= Buf->getBufferSize());
+ 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
// memory buffer Buf).
@@ -2664,7 +2691,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 > 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 89a03b3fe0ee35..95bea0964eaef3 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 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.test b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
new file mode 100644
index 00000000000000..fa6230e64bc77c
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/gap-fill.test
@@ -0,0 +1,176 @@
+# 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 %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 %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=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 %t.bin 2>&1 | FileCheck %s --check-prefix=BAD-INPUT4
+# BAD-INPUT4: error: --gap-fill: bad number: ff
+
+# 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)
+
+## 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
+# 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 --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
+# 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 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 --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.
+# 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 --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
+# 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
+ Size: 0x6
+ Content: 'EEFF11223344'
+ - Name: .gap1
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x0108
+ Content: 'AABBCCDDFEDCBA'
+ - Name: .space2
+ Type: Fill
+ Pattern: 'DC'
+ Size: 1
+ - Name: .gap2
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ Address: 0x0110
+ 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
+ Size: 0x0018
+ - Name: .space4
+ Type: Fill
+ Pattern: '01234567'
+ Size: 0x4
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0184
+ Content: '89ABCDEF'
+ - Name: .nobit_bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x018A
+ Size: 0x0008
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ EntSize: 0x0001
+ Content: 4743433A
+
+## 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.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
+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
+ Size: 4
+ - Name: .section1
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_WRITE ]
+ Address: 0x0108
+ Content: '11223344'
+ - Name: .section3
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_WRITE ]
+ Address: 0x0100
+ Content: 'AABBCCDD'
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..eb3608860a5433
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/pad-to.test
@@ -0,0 +1,90 @@
+# 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: 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: 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: 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: error: --pad-to: bad number: 0x112233445566778899
+
+## Save the baseline, not padded output.
+# RUN: llvm-objcopy -O binary %t %t.bin
+
+## 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
+# 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 --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 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
+# 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 --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
+
+## 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
+# 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
+ Size: 0x6
+ Content: '112233445566'
+ - Name: .space
+ Type: Fill
+ Pattern: '01234567'
+ Size: 0x4
+ - Name: .section2
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0210
+ Content: '778899aa'
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0220
+ Size: 0x0008
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ EntSize: 0x0001
+ Content: ''
+...
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index efc09f308f46fe..f15307181fad61 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -737,6 +737,35 @@ 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<uint64_t> Val = getAsInteger<uint64_t>(A->getValue());
+ if (!Val)
+ return createStringError(Val.getError(), "--gap-fill: bad number: %s",
+ 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());
+ Config.GapFill = ByteVal;
+ }
+
+ 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(), "--pad-to: bad number: %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..ead8cd28d38779 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 input and binary output">,
+ MetaVarName<"value">;
+
+defm pad_to
+ : 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 ELF input and binary output">,
+ MetaVarName<"address">;
More information about the llvm-commits
mailing list