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 <akary...@quicinc.com> Date: Tue, 5 Sep 2023 15:46:34 -0700 Subject: [PATCH 01/11] [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 <akary...@quicinc.com> Date: Thu, 14 Sep 2023 08:14:37 -0700 Subject: [PATCH 02/11] 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 <akary...@quicinc.com> Date: Wed, 4 Oct 2023 08:53:20 -0700 Subject: [PATCH 03/11] 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 <akary...@quicinc.com> Date: Mon, 30 Oct 2023 11:35:50 -0700 Subject: [PATCH 04/11] 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 <akary...@quicinc.com> Date: Mon, 30 Oct 2023 12:34:29 -0700 Subject: [PATCH 05/11] 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 <akary...@quicinc.com> Date: Tue, 31 Oct 2023 08:16:35 -0700 Subject: [PATCH 06/11] 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 <akary...@quicinc.com> Date: Mon, 11 Dec 2023 10:45:10 -0800 Subject: [PATCH 07/11] 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 <akary...@quicinc.com> Date: Mon, 11 Dec 2023 10:50:21 -0800 Subject: [PATCH 08/11] 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 <akary...@quicinc.com> Date: Mon, 11 Dec 2023 11:03:54 -0800 Subject: [PATCH 09/11] 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 <akary...@quicinc.com> Date: Tue, 12 Dec 2023 11:06:41 -0800 Subject: [PATCH 10/11] 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(); >From ed9893833b287bc23f1385badd845e7a97f2290b Mon Sep 17 00:00:00 2001 From: Alexey Karyakin <akary...@quicinc.com> Date: Tue, 12 Dec 2023 11:23:32 -0800 Subject: [PATCH 11/11] Remove thes. --- llvm/tools/llvm-objcopy/ObjcopyOpts.td | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td index a5363f4e0c3f01..ead8cd28d38779 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 the ELF input and binary output">, + "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 the ELF input and binary output">, + "This option is only supported for ELF input and binary output">, MetaVarName<"address">; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits