From 24308b26df6af7c9e027db9ef637a8da75fdf93f Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Wed, 27 Nov 2024 22:31:05 -0800 Subject: [PATCH 01/21] [llvm-objcopy][ELF] Add an option to remove notes This adds an option `--remove-note` to selectively delete notes in an ELF file. For now, it is expected to be useful for editing core dump files; in particular, it searches for the notes in `PT_NOTE` segments and does not handle nested segments. The implementation can be extended later as needed. --- llvm/include/llvm/ObjCopy/ELF/ELFConfig.h | 9 ++ llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 96 ++++++++++++++++++ llvm/lib/ObjCopy/ELF/ELFObject.cpp | 21 ++++ llvm/lib/ObjCopy/ELF/ELFObject.h | 5 + .../tools/llvm-objcopy/ELF/remove-note.test | 98 +++++++++++++++++++ llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 39 ++++++++ llvm/tools/llvm-objcopy/ObjcopyOpts.td | 4 + 7 files changed, 272 insertions(+) create mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note.test diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h index 59960b6530743..01a8762cfb9c3 100644 --- a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h +++ b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h @@ -15,6 +15,12 @@ namespace llvm { namespace objcopy { +// Note to remove info specified by --remove-note option. +struct RemoveNoteInfo { + StringRef Name; + uint32_t TypeId; +}; + // ELF specific configuration for copying/stripping a single file. struct ELFConfig { uint8_t NewSymbolVisibility = (uint8_t)ELF::STV_DEFAULT; @@ -31,6 +37,9 @@ struct ELFConfig { bool KeepFileSymbols = false; bool LocalizeHidden = false; bool VerifyNoteSections = true; + + // Notes specified by --remove-note option. + SmallVector NotesToRemove; }; } // namespace objcopy diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 4793651f1d4e0..1df64b0b7ce88 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -609,6 +609,97 @@ static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo, Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0); } +template +static Error removeNoteImpl(Object &Obj, + ArrayRef NotesToRemove) { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT); + for (Segment &Seg : Obj.segments()) { + // TODO: Support nested segments + if (Seg.Type != PT_NOTE || Seg.ParentSegment) + continue; + + // Find chunks of the segment data to remove + struct DeletedRange { + uint64_t OldFrom; + uint64_t OldTo; + uint64_t NewOffset; + }; + std::vector DataToRemove; + ArrayRef OldData = Seg.getContents(); + size_t Align = std::max(4, Seg.Align); + uint64_t Offset = 0; + while (Offset + sizeof(Elf_Nhdr) <= OldData.size()) { + auto Nhdr = reinterpret_cast(OldData.data() + Offset); + size_t FullSize = Nhdr->getSize(Align); + if (Offset + FullSize > OldData.size()) + break; + Elf_Note Note(*Nhdr); + if (llvm::any_of(NotesToRemove, [&](const RemoveNoteInfo &NoteInfo) { + return NoteInfo.TypeId == Note.getType() && + (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName()); + })) + DataToRemove.push_back({Offset, Offset + FullSize, 0}); + Offset += FullSize; + } + if (DataToRemove.empty()) + continue; + + // Prepare the new segment data + std::vector NewData; + NewData.reserve(OldData.size()); + Offset = 0; + for (auto &RemRange : DataToRemove) { + if (Offset < RemRange.OldFrom) { + auto Slice = OldData.slice(Offset, RemRange.OldFrom - Offset); + NewData.insert(NewData.end(), Slice.begin(), Slice.end()); + } + RemRange.NewOffset = NewData.size(); + Offset = RemRange.OldTo; + } + if (Offset < OldData.size()) { + auto Slice = OldData.slice(Offset); + NewData.insert(NewData.end(), Slice.begin(), Slice.end()); + } + + auto CalculateNewOffset = [&](uint64_t SecOffset) { + uint64_t Offset = SecOffset - Seg.Offset; + auto It = + llvm::upper_bound(DataToRemove, Offset, + [](const uint64_t &Off, const DeletedRange &Range) { + return Off < Range.OldFrom; + }); + if (It != DataToRemove.begin()) { + --It; + Offset = (Offset > It->OldTo) ? (Offset - It->OldTo + It->NewOffset) + : It->NewOffset; + } + return Offset + Seg.Offset; + }; + + // Remap the segment's sections + DenseMap> Mapping; + for (const SectionBase *Sec : Seg.Sections) { + uint64_t NewOffset = CalculateNewOffset(Sec->Offset); + uint64_t NewSize = + CalculateNewOffset(Sec->Offset + Sec->Size) - NewOffset; + Mapping.try_emplace(Sec, NewOffset, NewSize); + } + + Obj.updateSegmentData(Seg, std::move(NewData), Mapping); + } + return Error::success(); +} + +static Error removeNote(Object &Obj, endianness Endianness, + ArrayRef NotesToRemove) { + // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the + // header, so the parsers are the same. + if (Endianness == endianness::little) + return removeNoteImpl(Obj, NotesToRemove); + else + return removeNoteImpl(Obj, NotesToRemove); +} + static Error handleUserSection(const NewSectionInfo &NewSection, function_ref)> F) { @@ -799,6 +890,11 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, ? endianness::little : endianness::big; + if (!ELFConfig.NotesToRemove.empty()) { + if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove)) + return Err; + } + for (const NewSectionInfo &AddedSection : Config.AddSection) { auto AddSection = [&](StringRef Name, ArrayRef Data) -> Error { OwnedDataSection &NewSection = diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp index 01c2f24629077..9f460f685706c 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2308,6 +2308,27 @@ Error Object::addNewSymbolTable() { return Error::success(); } +void Object::updateSegmentData( + Segment &S, std::vector NewSegmentData, + const DenseMap> + &SectionMapping) { + auto It = + UpdatedSegments.insert_or_assign(&S, std::move(NewSegmentData)).first; + S.Contents = It->second; + S.FileSize = S.Contents.size(); + if (S.MemSize) + S.MemSize = S.FileSize; + assert(SectionMapping.size() == S.Sections.size()); + for (const auto &SM : SectionMapping) { + assert(SM.first->ParentSegment == &S && S.Sections.count(SM.first)); + assert(SM.second.first >= S.Offset); + assert((SM.second.first + SM.second.second) <= (S.Offset + S.FileSize)); + SectionBase *MutSec = const_cast(SM.first); + MutSec->Offset = SM.second.first; + MutSec->Size = SM.second.second; + } +} + // Orders segments such that if x = y->ParentSegment then y comes before x. static void orderSegments(std::vector &Segments) { llvm::stable_sort(Segments, compareSegmentsByOffset); diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h index 6ccf85387131e..5e16d4c0c1885 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.h +++ b/llvm/lib/ObjCopy/ELF/ELFObject.h @@ -1159,6 +1159,7 @@ class Object { std::vector Segments; std::vector RemovedSections; DenseMap> UpdatedSections; + DenseMap> UpdatedSegments; static bool sectionIsAlloc(const SectionBase &Sec) { return Sec.Flags & ELF::SHF_ALLOC; @@ -1234,6 +1235,10 @@ class Object { Segments.emplace_back(std::make_unique(Data)); return *Segments.back(); } + void updateSegmentData( + Segment &S, std::vector NewSegmentData, + const DenseMap> + &SectionMapping); bool isRelocatable() const { return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable; } diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test new file mode 100644 index 0000000000000..b24538e26d019 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -0,0 +1,98 @@ +# RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID +# RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME +# RUN: not llvm-objcopy --remove-note=CORE/1/2 - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM1 +# RUN: not llvm-objcopy --remove-note=Notanumber - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM2 +# RUN: not llvm-objcopy --remove-note=CORE/Notanumber - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM2 + +# ERR-NOTYPEID: error: bad format for --remove-note, missing type_id +# ERR-EMPTYNAME: error: bad format for --remove-note, note name is empty +# ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2' +# ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber' + +# RUN: yaml2obj -D ALIGN=8 %s -o - \ +# RUN: | llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/0x03 - - \ +# RUN: | llvm-readobj --segments --sections --notes - \ +# RUN: | FileCheck %s -D#SIZE=64 + +# RUN: yaml2obj -D ALIGN=4 %s -o - \ +# RUN: | llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/0x03 - - \ +# RUN: | llvm-readobj --segments --sections --notes - \ +# RUN: | FileCheck %s -D#SIZE=48 + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Name: .note +# CHECK-NEXT: Type: SHT_NOTE +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: [[OFFSET:0x.+]] +# CHECK-NEXT: Size: [[#%d,SIZE]] + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_NOTE +# CHECK-NEXT: Offset: [[OFFSET]] +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: [[#%d,SIZE]] +# CHECK-NEXT: MemSize: 0 + +# CHECK: NoteSections [ +# CHECK-NEXT: NoteSection { +# CHECK-NEXT: Name: +# CHECK-NEXT: Offset: [[OFFSET]] +# CHECK-NEXT: Size: 0x[[#%x,SIZE]] +# CHECK-NEXT: Notes [ +# CHECK-NEXT: { +# CHECK-NEXT: Owner: CORE +# CHECK-NEXT: Data size: 0x2 +# CHECK-NEXT: Type: NT_FPREGSET +# CHECK-NEXT: Description data ( +# CHECK-NEXT: 0000: 0202 +# CHECK-NEXT: ) +# CHECK-NEXT: } +# CHECK-NEXT: { +# CHECK-NEXT: Owner: CORE +# CHECK-NEXT: Data size: 0x2 +# CHECK-NEXT: Type: NT_TASKSTRUCT +# CHECK-NEXT: Description data ( +# CHECK-NEXT: 0000: 0404 +# CHECK-NEXT: ) +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_CORE + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_NOTE + MemSize: 0 + FirstSec: .note + LastSec: .note +Sections: + - Name: .note + Type: SHT_NOTE + AddressAlign: [[ALIGN]] + Notes: + - Name: CORE + Type: 0x01 + Desc: 0101 + - Name: CORE + Type: 0x02 + Desc: 0202 + - Name: CORE + Type: 0x03 + Desc: 0303 + - Name: CORE + Type: 0x04 + Desc: 0404 + - Name: LINUX + Type: 0x01 + Desc: 0505 +... diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp index 104d802b1e1ee..5e348d65adca1 100644 --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -527,6 +527,37 @@ static Expected parseNewSymbolInfo(StringRef FlagValue) { return SI; } +static Expected parseRemoveNoteInfo(StringRef FlagValue) { + // Parse value given with --remove-note option. The format is: + // + // [name/]type_id + // + // where: + // - optional note name. If not given, all notes with the specified + // are removed. + // - note type value, can be decimal or hexadecimal number prefixed + // with 0x. + RemoveNoteInfo NI; + if (FlagValue.empty()) + return createStringError(errc::invalid_argument, + "bad format for --remove-note, missing type_id"); + SmallVector Tokens; + FlagValue.split(Tokens, '/', /*MaxSplit=*/1); + assert(!Tokens.empty() && Tokens.size() <= 2); + if (Tokens.size() == 2) { + if (Tokens[0].empty()) + return createStringError( + errc::invalid_argument, + "bad format for --remove-note, note name is empty"); + NI.Name = Tokens[0]; + } + if (Tokens.back().getAsInteger(0, NI.TypeId)) + return createStringError(errc::invalid_argument, + "bad note type_id for --remove-note: '%s'", + Tokens.back().str().c_str()); + return NI; +} + // Parse input option \p ArgValue and load section data. This function // extracts section name and name of the file keeping section data from // ArgValue, loads data from the file, and stores section name and data @@ -1210,6 +1241,14 @@ objcopy::parseObjcopyOptions(ArrayRef ArgsArr, }; } + for (auto *Arg : InputArgs.filtered(OBJCOPY_remove_note)) { + Expected NoteInfo = parseRemoveNoteInfo(Arg->getValue()); + if (!NoteInfo) + return NoteInfo.takeError(); + + ELFConfig.NotesToRemove.push_back(*NoteInfo); + } + if (Config.DecompressDebugSections && Config.CompressionType != DebugCompressionType::None) { return createStringError( diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td index 434b5ff92324e..fbc6a59d9461e 100644 --- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td +++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td @@ -297,3 +297,7 @@ defm pad_to "of zero or the value specified by the --gap-fill option. " "This option is only supported for ELF input and binary output">, MetaVarName<"address">; + +defm remove_note + : Eq<"remove-note", "Remove note(s) with and optional ">, + MetaVarName<"[name/]type_id">; From 3550f3afd72092e1664b3c3d46b8f1a5fce7c5a3 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 13 Dec 2024 22:35:09 -0800 Subject: [PATCH 02/21] fixup: update parsing the argument --- llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp index bfd67c558074e..a5643f0bec5d9 100644 --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -549,23 +549,24 @@ static Expected parseRemoveNoteInfo(StringRef FlagValue) { // - note type value, can be decimal or hexadecimal number prefixed // with 0x. RemoveNoteInfo NI; - if (FlagValue.empty()) - return createStringError(errc::invalid_argument, - "bad format for --remove-note, missing type_id"); - SmallVector Tokens; - FlagValue.split(Tokens, '/', /*MaxSplit=*/1); - assert(!Tokens.empty() && Tokens.size() <= 2); - if (Tokens.size() == 2) { - if (Tokens[0].empty()) + StringRef TypeIdStr; + if (auto Idx = FlagValue.find('/'); Idx != StringRef::npos) { + if (Idx == 0) return createStringError( errc::invalid_argument, "bad format for --remove-note, note name is empty"); - NI.Name = Tokens[0]; + NI.Name = FlagValue.slice(0, Idx); + TypeIdStr = FlagValue.substr(Idx + 1); + } else { + TypeIdStr = FlagValue; } - if (Tokens.back().getAsInteger(0, NI.TypeId)) + if (TypeIdStr.empty()) + return createStringError(errc::invalid_argument, + "bad format for --remove-note, missing type_id"); + if (TypeIdStr.getAsInteger(0, NI.TypeId)) return createStringError(errc::invalid_argument, "bad note type_id for --remove-note: '%s'", - Tokens.back().str().c_str()); + TypeIdStr.str().c_str()); return NI; } From 51b05f292ac7475722eedb3f9e1e11040e608dc0 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 13 Dec 2024 22:35:34 -0800 Subject: [PATCH 03/21] fixup: update tests --- llvm/test/tools/llvm-objcopy/ELF/remove-note.test | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index b24538e26d019..258ec06fba321 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -1,4 +1,5 @@ # RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID +# RUN: not llvm-objcopy --remove-note=CORE/ - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID # RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME # RUN: not llvm-objcopy --remove-note=CORE/1/2 - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM1 # RUN: not llvm-objcopy --remove-note=Notanumber - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM2 @@ -9,15 +10,13 @@ # ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2' # ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber' -# RUN: yaml2obj -D ALIGN=8 %s -o - \ -# RUN: | llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/0x03 - - \ -# RUN: | llvm-readobj --segments --sections --notes - \ -# RUN: | FileCheck %s -D#SIZE=64 +# RUN: yaml2obj -D ALIGN=8 %s -o %t8 +# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8 %t8o +# RUN: llvm-readobj --segments --sections --notes %t8o | FileCheck %s -D#SIZE=64 -# RUN: yaml2obj -D ALIGN=4 %s -o - \ -# RUN: | llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/0x03 - - \ -# RUN: | llvm-readobj --segments --sections --notes - \ -# RUN: | FileCheck %s -D#SIZE=48 +# RUN: yaml2obj -D ALIGN=4 %s -o %t4 +# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4 %t4o +# RUN: llvm-readobj --segments --sections --notes %t4o | FileCheck %s -D#SIZE=48 # CHECK: Sections [ # CHECK: Section { From 1bad501c0095b9f4656766f6849848268495a06e Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 13 Dec 2024 22:48:40 -0800 Subject: [PATCH 04/21] fixup: add the option to the command guide --- llvm/docs/CommandGuide/llvm-objcopy.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst index e6af47ce9710a..c57d367261a12 100644 --- a/llvm/docs/CommandGuide/llvm-objcopy.rst +++ b/llvm/docs/CommandGuide/llvm-objcopy.rst @@ -464,6 +464,11 @@ them. Preserve access and modification timestamps in the output. +.. option:: --remove-note [/] + + Remove notes of integer type ```` and name ```` from SHT_NOTE + sections and PT_NOTE segments. Can be specified multiple times. + .. option:: --rename-section =[,,...] Rename sections called ```` to ```` in the output, and apply any From 3b17fdb705a4ae7ab622bb1c85a13f7821f5570f Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Thu, 19 Dec 2024 18:34:46 -0800 Subject: [PATCH 05/21] fixup: fix updating offsets --- llvm/lib/ObjCopy/ELF/ELFObject.cpp | 9 +++- .../tools/llvm-objcopy/ELF/remove-note.test | 46 ++++++++++++++----- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp index 9f460f685706c..5f2cef8ac8604 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2312,6 +2312,11 @@ void Object::updateSegmentData( Segment &S, std::vector NewSegmentData, const DenseMap> &SectionMapping) { + // TODO: Update the parent segment + assert(!S.ParentSegment); + // TODO: Update nested segments + assert(!llvm::any_of( + Segments, [&S](const SegPtr &Seg) { return Seg->ParentSegment == &S; })); auto It = UpdatedSegments.insert_or_assign(&S, std::move(NewSegmentData)).first; S.Contents = It->second; @@ -2319,12 +2324,14 @@ void Object::updateSegmentData( if (S.MemSize) S.MemSize = S.FileSize; assert(SectionMapping.size() == S.Sections.size()); + assert(S.Offset == S.OriginalOffset); for (const auto &SM : SectionMapping) { assert(SM.first->ParentSegment == &S && S.Sections.count(SM.first)); assert(SM.second.first >= S.Offset); assert((SM.second.first + SM.second.second) <= (S.Offset + S.FileSize)); + assert(SM.first->Offset == SM.first->OriginalOffset); SectionBase *MutSec = const_cast(SM.first); - MutSec->Offset = SM.second.first; + MutSec->OriginalOffset = MutSec->Offset = SM.second.first; MutSec->Size = SM.second.second; } } diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index 258ec06fba321..8475e3f8c3173 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -12,36 +12,50 @@ # RUN: yaml2obj -D ALIGN=8 %s -o %t8 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8 %t8o -# RUN: llvm-readobj --segments --sections --notes %t8o | FileCheck %s -D#SIZE=64 +# RUN: llvm-readobj --segments --sections --notes %t8o | FileCheck %s -D#SIZE0=32 -D#SIZE1=32 # RUN: yaml2obj -D ALIGN=4 %s -o %t4 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4 %t4o -# RUN: llvm-readobj --segments --sections --notes %t4o | FileCheck %s -D#SIZE=48 +# RUN: llvm-readobj --segments --sections --notes %t4o | FileCheck %s -D#SIZE0=24 -D#SIZE1=24 # CHECK: Sections [ # CHECK: Section { -# CHECK: Name: .note +# CHECK: Name: .note0 # CHECK-NEXT: Type: SHT_NOTE # CHECK-NEXT: Flags [ # CHECK-NEXT: ] # CHECK-NEXT: Address: -# CHECK-NEXT: Offset: [[OFFSET:0x.+]] -# CHECK-NEXT: Size: [[#%d,SIZE]] +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0:]] +# CHECK-NEXT: Size: [[#%d,SIZE0]] +# CHECK: Name: .note1 +# CHECK-NEXT: Type: SHT_NOTE +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0]] +# CHECK-NEXT: Size: [[#%d,SIZE1]] +# CHECK: Name: .note2 +# CHECK-NEXT: Type: SHT_NOTE +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]] +# CHECK-NEXT: Size: 0 # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_NOTE -# CHECK-NEXT: Offset: [[OFFSET]] +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0]] # CHECK-NEXT: VirtualAddress: 0x0 # CHECK-NEXT: PhysicalAddress: 0x0 -# CHECK-NEXT: FileSize: [[#%d,SIZE]] +# CHECK-NEXT: FileSize: [[#%d,SIZE0+SIZE1]] # CHECK-NEXT: MemSize: 0 # CHECK: NoteSections [ # CHECK-NEXT: NoteSection { # CHECK-NEXT: Name: -# CHECK-NEXT: Offset: [[OFFSET]] -# CHECK-NEXT: Size: 0x[[#%x,SIZE]] +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0]] +# CHECK-NEXT: Size: 0x[[#%X,SIZE0+SIZE1]] # CHECK-NEXT: Notes [ # CHECK-NEXT: { # CHECK-NEXT: Owner: CORE @@ -72,10 +86,10 @@ FileHeader: ProgramHeaders: - Type: PT_NOTE MemSize: 0 - FirstSec: .note - LastSec: .note + FirstSec: .note0 + LastSec: .note2 Sections: - - Name: .note + - Name: .note0 Type: SHT_NOTE AddressAlign: [[ALIGN]] Notes: @@ -85,12 +99,20 @@ Sections: - Name: CORE Type: 0x02 Desc: 0202 + - Name: .note1 + Type: SHT_NOTE + AddressAlign: [[ALIGN]] + Notes: - Name: CORE Type: 0x03 Desc: 0303 - Name: CORE Type: 0x04 Desc: 0404 + - Name: .note2 + Type: SHT_NOTE + AddressAlign: [[ALIGN]] + Notes: - Name: LINUX Type: 0x01 Desc: 0505 From 1c84760cbce5a9815fc385de58b9e6f0ffccf1ee Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Thu, 19 Dec 2024 19:52:07 -0800 Subject: [PATCH 06/21] fixup: split 'removeNote()' --- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 179 ++++++++++++++++------------ llvm/lib/ObjCopy/ELF/ELFObject.h | 8 +- 2 files changed, 107 insertions(+), 80 deletions(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 1df64b0b7ce88..9401310bf2750 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -609,95 +609,122 @@ static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo, Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0); } +namespace { +struct RemoveNoteDetail { + struct DeletedRange { + uint64_t OldFrom; + uint64_t OldTo; + uint64_t NewPos; + }; + + template + static std::vector + findNotesToRemove(ArrayRef Data, size_t Align, + ArrayRef NotesToRemove); + static std::vector updateData(ArrayRef OldData, + ArrayRef ToRemove); + static Object::Section2OffsetAndSize + getSectionMapping(const Segment &Seg, ArrayRef ToRemove); +}; + +} // namespace + template -static Error removeNoteImpl(Object &Obj, - ArrayRef NotesToRemove) { +std::vector +RemoveNoteDetail::findNotesToRemove(ArrayRef Data, size_t Align, + ArrayRef NotesToRemove) { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT); - for (Segment &Seg : Obj.segments()) { - // TODO: Support nested segments - if (Seg.Type != PT_NOTE || Seg.ParentSegment) - continue; - - // Find chunks of the segment data to remove - struct DeletedRange { - uint64_t OldFrom; - uint64_t OldTo; - uint64_t NewOffset; - }; - std::vector DataToRemove; - ArrayRef OldData = Seg.getContents(); - size_t Align = std::max(4, Seg.Align); - uint64_t Offset = 0; - while (Offset + sizeof(Elf_Nhdr) <= OldData.size()) { - auto Nhdr = reinterpret_cast(OldData.data() + Offset); - size_t FullSize = Nhdr->getSize(Align); - if (Offset + FullSize > OldData.size()) - break; - Elf_Note Note(*Nhdr); - if (llvm::any_of(NotesToRemove, [&](const RemoveNoteInfo &NoteInfo) { - return NoteInfo.TypeId == Note.getType() && - (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName()); - })) - DataToRemove.push_back({Offset, Offset + FullSize, 0}); - Offset += FullSize; - } - if (DataToRemove.empty()) - continue; + std::vector ToRemove; + uint64_t CurPos = 0; + uint64_t NewPos = 0; + while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) { + auto Nhdr = reinterpret_cast(Data.data() + CurPos); + size_t FullSize = Nhdr->getSize(Align); + if (CurPos + FullSize > Data.size()) + break; + Elf_Note Note(*Nhdr); + bool ShouldRemove = + llvm::any_of(NotesToRemove, [&Note](const RemoveNoteInfo &NoteInfo) { + return NoteInfo.TypeId == Note.getType() && + (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName()); + }); + if (ShouldRemove) + ToRemove.push_back({CurPos, CurPos + FullSize, NewPos}); + else + NewPos += FullSize; + CurPos += FullSize; + } + return ToRemove; +} - // Prepare the new segment data - std::vector NewData; - NewData.reserve(OldData.size()); - Offset = 0; - for (auto &RemRange : DataToRemove) { - if (Offset < RemRange.OldFrom) { - auto Slice = OldData.slice(Offset, RemRange.OldFrom - Offset); - NewData.insert(NewData.end(), Slice.begin(), Slice.end()); - } - RemRange.NewOffset = NewData.size(); - Offset = RemRange.OldTo; - } - if (Offset < OldData.size()) { - auto Slice = OldData.slice(Offset); +std::vector +RemoveNoteDetail::updateData(ArrayRef OldData, + ArrayRef ToRemove) { + std::vector NewData; + NewData.reserve(OldData.size()); + uint64_t CurPos = 0; + for (auto &RemRange : ToRemove) { + if (CurPos < RemRange.OldFrom) { + auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos); NewData.insert(NewData.end(), Slice.begin(), Slice.end()); } + assert(RemRange.NewPos == NewData.size()); + CurPos = RemRange.OldTo; + } + if (CurPos < OldData.size()) { + auto Slice = OldData.slice(CurPos); + NewData.insert(NewData.end(), Slice.begin(), Slice.end()); + } + return NewData; +} - auto CalculateNewOffset = [&](uint64_t SecOffset) { - uint64_t Offset = SecOffset - Seg.Offset; - auto It = - llvm::upper_bound(DataToRemove, Offset, - [](const uint64_t &Off, const DeletedRange &Range) { - return Off < Range.OldFrom; - }); - if (It != DataToRemove.begin()) { - --It; - Offset = (Offset > It->OldTo) ? (Offset - It->OldTo + It->NewOffset) - : It->NewOffset; - } - return Offset + Seg.Offset; - }; - - // Remap the segment's sections - DenseMap> Mapping; - for (const SectionBase *Sec : Seg.Sections) { - uint64_t NewOffset = CalculateNewOffset(Sec->Offset); - uint64_t NewSize = - CalculateNewOffset(Sec->Offset + Sec->Size) - NewOffset; - Mapping.try_emplace(Sec, NewOffset, NewSize); +Object::Section2OffsetAndSize +RemoveNoteDetail::getSectionMapping(const Segment &Seg, + ArrayRef ToRemove) { + auto CalculateNewOffset = [&](uint64_t SecOffset) { + uint64_t Pos = SecOffset - Seg.Offset; + auto It = llvm::upper_bound( + ToRemove, Pos, [](const uint64_t &Pos, const DeletedRange &Range) { + return Pos < Range.OldFrom; + }); + if (It != ToRemove.begin()) { + --It; + Pos = (Pos > It->OldTo) ? (Pos - It->OldTo + It->NewPos) : It->NewPos; } + return Pos + Seg.Offset; + }; - Obj.updateSegmentData(Seg, std::move(NewData), Mapping); + // Remap the segment's sections + Object::Section2OffsetAndSize Mapping; + for (const SectionBase *Sec : Seg.Sections) { + uint64_t NewOffset = CalculateNewOffset(Sec->Offset); + uint64_t NewSize = CalculateNewOffset(Sec->Offset + Sec->Size) - NewOffset; + Mapping.try_emplace(Sec, NewOffset, NewSize); } - return Error::success(); + return Mapping; } static Error removeNote(Object &Obj, endianness Endianness, ArrayRef NotesToRemove) { - // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the - // header, so the parsers are the same. - if (Endianness == endianness::little) - return removeNoteImpl(Obj, NotesToRemove); - else - return removeNoteImpl(Obj, NotesToRemove); + for (Segment &Seg : Obj.segments()) { + // TODO: Support nested segments + if (Seg.Type != PT_NOTE || Seg.ParentSegment) + continue; + ArrayRef OldData = Seg.getContents(); + size_t Align = std::max(4, Seg.Align); + // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the + // header, so the parsers are the same. + auto ToRemove = (Endianness == endianness::little) + ? RemoveNoteDetail::findNotesToRemove( + OldData, Align, NotesToRemove) + : RemoveNoteDetail::findNotesToRemove( + OldData, Align, NotesToRemove); + if (!ToRemove.empty()) + Obj.updateSegmentData(Seg, + RemoveNoteDetail::updateData(OldData, ToRemove), + RemoveNoteDetail::getSectionMapping(Seg, ToRemove)); + } + return Error::success(); } static Error diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h index 5e16d4c0c1885..fc518327c1be1 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.h +++ b/llvm/lib/ObjCopy/ELF/ELFObject.h @@ -1235,10 +1235,10 @@ class Object { Segments.emplace_back(std::make_unique(Data)); return *Segments.back(); } - void updateSegmentData( - Segment &S, std::vector NewSegmentData, - const DenseMap> - &SectionMapping); + using OffsetAndSize = std::pair; + using Section2OffsetAndSize = DenseMap; + void updateSegmentData(Segment &S, std::vector NewSegmentData, + const Section2OffsetAndSize &SectionMapping); bool isRelocatable() const { return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable; } From f6d4330cf26dad70e4fb08ff319ffd8c5f057349 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Thu, 19 Dec 2024 20:16:22 -0800 Subject: [PATCH 07/21] fixup: do not allow '--remove-note' with '--(remove|add|update)-section' --- llvm/test/tools/llvm-objcopy/ELF/remove-note.test | 10 ++++++++++ llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index 8475e3f8c3173..6eaeda9528a86 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -1,3 +1,13 @@ +## Check incompatible options +# RUN: not llvm-objcopy --remove-note=1 --remove-section=.test - 2>&1 | FileCheck %s --check-prefix=ERR-REMSEC +# RUN: not llvm-objcopy --remove-note=1 --add-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-ADDSEC +# RUN: not llvm-objcopy --remove-note=1 --update-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-UPDSEC + +# ERR-REMSEC: error: cannot specify both --remove-note and --remove-section +# ERR-ADDSEC: error: cannot specify both --remove-note and --add-section +# ERR-UPDSEC: error: cannot specify both --remove-note and --update-section + +## Check invalid argument formats # RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID # RUN: not llvm-objcopy --remove-note=CORE/ - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID # RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp index a5643f0bec5d9..0d209590655ef 100644 --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -1261,6 +1261,21 @@ objcopy::parseObjcopyOptions(ArrayRef ArgsArr, ELFConfig.NotesToRemove.push_back(*NoteInfo); } + if (!ELFConfig.NotesToRemove.empty()) { + if (!Config.ToRemove.empty()) + return createStringError( + errc::invalid_argument, + "cannot specify both --remove-note and --remove-section"); + if (!Config.AddSection.empty()) + return createStringError( + errc::invalid_argument, + "cannot specify both --remove-note and --add-section"); + if (!Config.UpdateSection.empty()) + return createStringError( + errc::invalid_argument, + "cannot specify both --remove-note and --update-section"); + } + if (Config.DecompressDebugSections && Config.CompressionType != DebugCompressionType::None) { return createStringError( From fd72505eb22a4320463ed01fb54ed15a1c44c24b Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 20 Dec 2024 19:33:59 -0800 Subject: [PATCH 08/21] fixup: change ELF type of the test file ET_CORE -> ET_EXEC For core files, llvm-readobj dumps note segments as a whole, without reporting individual sections. --- .../tools/llvm-objcopy/ELF/remove-note.test | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index 6eaeda9528a86..768949e2687f0 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -63,35 +63,49 @@ # CHECK: NoteSections [ # CHECK-NEXT: NoteSection { -# CHECK-NEXT: Name: +# CHECK-NEXT: Name: .note0 # CHECK-NEXT: Offset: 0x[[#%X,OFFSET0]] -# CHECK-NEXT: Size: 0x[[#%X,SIZE0+SIZE1]] +# CHECK-NEXT: Size: 0x[[#%X,SIZE0]] # CHECK-NEXT: Notes [ # CHECK-NEXT: { # CHECK-NEXT: Owner: CORE # CHECK-NEXT: Data size: 0x2 -# CHECK-NEXT: Type: NT_FPREGSET +# CHECK-NEXT: Type: NT_ARCH # CHECK-NEXT: Description data ( # CHECK-NEXT: 0000: 0202 # CHECK-NEXT: ) # CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: NoteSection { +# CHECK-NEXT: Name: .note1 +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0]] +# CHECK-NEXT: Size: 0x[[#%X,SIZE1]] +# CHECK-NEXT: Notes [ # CHECK-NEXT: { # CHECK-NEXT: Owner: CORE # CHECK-NEXT: Data size: 0x2 -# CHECK-NEXT: Type: NT_TASKSTRUCT +# CHECK-NEXT: Type: Unknown (0x00000004) # CHECK-NEXT: Description data ( # CHECK-NEXT: 0000: 0404 # CHECK-NEXT: ) # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } +# CHECK-NEXT: NoteSection { +# CHECK-NEXT: Name: .note2 +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]] +# CHECK-NEXT: Size: 0x0 +# CHECK-NEXT: Notes [ +# CHECK-NEXT: ] +# CHECK-NEXT: } # CHECK-NEXT: ] --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB - Type: ET_CORE + Type: ET_EXEC Machine: EM_X86_64 ProgramHeaders: - Type: PT_NOTE From e730cfdaf0ffe463c2692d3dbf98c6da1a0a06bc Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 20 Dec 2024 19:44:47 -0800 Subject: [PATCH 09/21] fixup: also run the test for ELF32 and BE --- .../tools/llvm-objcopy/ELF/remove-note.test | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index 768949e2687f0..2053e76593fad 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -20,13 +20,20 @@ # ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2' # ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber' -# RUN: yaml2obj -D ALIGN=8 %s -o %t8 -# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8 %t8o -# RUN: llvm-readobj --segments --sections --notes %t8o | FileCheck %s -D#SIZE0=32 -D#SIZE1=32 +# RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb +# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o +# RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \ +# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=32 -# RUN: yaml2obj -D ALIGN=4 %s -o %t4 -# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4 %t4o -# RUN: llvm-readobj --segments --sections --notes %t4o | FileCheck %s -D#SIZE0=24 -D#SIZE1=24 +# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb +# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o +# RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \ +# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 + +# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb +# RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o +# RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \ +# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 # CHECK: Sections [ # CHECK: Section { @@ -103,8 +110,8 @@ --- !ELF FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB + Class: ELFCLASS[[ELFCLASS]] + Data: ELFDATA2[[ENDIANNESS]] Type: ET_EXEC Machine: EM_X86_64 ProgramHeaders: From de674542e110dd27a1e42c42301b53aad089efad Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 20 Dec 2024 19:46:44 -0800 Subject: [PATCH 10/21] fixup: handle SHT_NOTE sections outside of segments --- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 18 ++++++++ llvm/lib/ObjCopy/ELF/ELFObject.cpp | 29 +++++++++---- llvm/lib/ObjCopy/ELF/ELFObject.h | 8 ++++ .../tools/llvm-objcopy/ELF/remove-note.test | 41 +++++++++++++++++-- 4 files changed, 84 insertions(+), 12 deletions(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 9401310bf2750..e7c5cff489d94 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -724,6 +724,24 @@ static Error removeNote(Object &Obj, endianness Endianness, RemoveNoteDetail::updateData(OldData, ToRemove), RemoveNoteDetail::getSectionMapping(Seg, ToRemove)); } + for (auto &Sec : Obj.sections()) { + if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents()) + continue; + ArrayRef OldData = Sec.getContents(); + size_t Align = std::max(4, Sec.Align); + // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the + // header, so the parsers are the same. + auto ToRemove = (Endianness == endianness::little) + ? RemoveNoteDetail::findNotesToRemove( + OldData, Align, NotesToRemove) + : RemoveNoteDetail::findNotesToRemove( + OldData, Align, NotesToRemove); + if (!ToRemove.empty()) { + if (Error E = Obj.updateSectionData( + Sec, RemoveNoteDetail::updateData(OldData, ToRemove))) + return E; + } + } return Error::success(); } diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp index 5f2cef8ac8604..8e547fe552931 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2154,25 +2154,20 @@ ELFWriter::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH, : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), OnlyKeepDebug(OnlyKeepDebug) {} -Error Object::updateSection(StringRef Name, ArrayRef Data) { - auto It = llvm::find_if(Sections, - [&](const SecPtr &Sec) { return Sec->Name == Name; }); - if (It == Sections.end()) - return createStringError(errc::invalid_argument, "section '%s' not found", - Name.str().c_str()); - +Error Object::updateSectionData(std::vector::iterator It, + ArrayRef Data) { auto *OldSec = It->get(); if (!OldSec->hasContents()) return createStringError( errc::invalid_argument, "section '%s' cannot be updated because it does not have contents", - Name.str().c_str()); + OldSec->Name.c_str()); if (Data.size() > OldSec->Size && OldSec->ParentSegment) return createStringError(errc::invalid_argument, "cannot fit data of size %zu into section '%s' " "with size %" PRIu64 " that is part of a segment", - Data.size(), Name.str().c_str(), OldSec->Size); + Data.size(), OldSec->Name.c_str(), OldSec->Size); if (!OldSec->ParentSegment) { *It = std::make_unique(*OldSec, Data); @@ -2185,6 +2180,22 @@ Error Object::updateSection(StringRef Name, ArrayRef Data) { return Error::success(); } +Error Object::updateSection(StringRef Name, ArrayRef Data) { + auto It = llvm::find_if(Sections, + [&](const SecPtr &Sec) { return Sec->Name == Name; }); + if (It == Sections.end()) + return createStringError(errc::invalid_argument, "section '%s' not found", + Name.str().c_str()); + return updateSectionData(It, Data); +} + +Error Object::updateSectionData(SectionBase &S, ArrayRef Data) { + auto It = llvm::find_if(Sections, + [&](const SecPtr &Sec) { return Sec.get() == &S; }); + assert(It != Sections.end() && "The section should belong to the object"); + return updateSectionData(It, Data); +} + Error Object::removeSections( bool AllowBrokenLinks, std::function ToRemove) { diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h index fc518327c1be1..285dd0bc12445 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.h +++ b/llvm/lib/ObjCopy/ELF/ELFObject.h @@ -549,6 +549,7 @@ class SectionBase { virtual void replaceSectionReferences(const DenseMap &); virtual bool hasContents() const { return false; } + virtual ArrayRef getContents() const { return {}; } // Notify the section that it is subject to removal. virtual void onRemove(); @@ -619,6 +620,8 @@ class Section : public SectionBase { bool hasContents() const override { return Type != ELF::SHT_NOBITS && Type != ELF::SHT_NULL; } + ArrayRef getContents() const override { return Contents; } + void restoreSymTabLink(SymbolTableSection &SymTab) override; }; @@ -654,6 +657,7 @@ class OwnedDataSection : public SectionBase { Error accept(SectionVisitor &Sec) const override; Error accept(MutableSectionVisitor &Visitor) override; bool hasContents() const override { return true; } + ArrayRef getContents() const override { return Data; } }; class CompressedSection : public SectionBase { @@ -1165,6 +1169,9 @@ class Object { return Sec.Flags & ELF::SHF_ALLOC; }; + Error updateSectionData(std::vector::iterator SecIt, + ArrayRef Data); + public: template using ConstRange = iterator_range Data); + Error updateSectionData(SectionBase &S, ArrayRef Data); SectionBase *findSection(StringRef Name) { auto SecIt = diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index 2053e76593fad..ecb39dba5ab6d 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -23,17 +23,17 @@ # RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o # RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \ -# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=32 +# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=32 -D#SIZE3=32 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o # RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \ -# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 +# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 -D#SIZE3=24 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb # RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o # RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \ -# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 +# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 -D#SIZE3=24 # CHECK: Sections [ # CHECK: Section { @@ -58,6 +58,13 @@ # CHECK-NEXT: Address: # CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]] # CHECK-NEXT: Size: 0 +# CHECK: Name: .note3 +# CHECK-NEXT: Type: SHT_NOTE +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET3:]] +# CHECK-NEXT: Size: [[#%d,SIZE3]] # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { @@ -106,6 +113,21 @@ # CHECK-NEXT: Notes [ # CHECK-NEXT: ] # CHECK-NEXT: } +# CHECK-NEXT: NoteSection { +# CHECK-NEXT: Name: .note3 +# CHECK-NEXT: Offset: 0x[[#%X,OFFSET3]] +# CHECK-NEXT: Size: 0x[[#%X,SIZE3]] +# CHECK-NEXT: Notes [ +# CHECK-NEXT: { +# CHECK-NEXT: Owner: CORE +# CHECK-NEXT: Data size: 0x2 +# CHECK-NEXT: Type: NT_ARCH +# CHECK-NEXT: Description data ( +# CHECK-NEXT: 0000: 0707 +# CHECK-NEXT: ) +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } # CHECK-NEXT: ] --- !ELF @@ -147,4 +169,17 @@ Sections: - Name: LINUX Type: 0x01 Desc: 0505 + - Name: .note3 + Type: SHT_NOTE + AddressAlign: [[ALIGN]] + Notes: + - Name: GNU + Type: 0x01 + Desc: 0606 + - Name: CORE + Type: 0x02 + Desc: 0707 + - Name: CORE + Type: 0x03 + Desc: 0808 ... From 95b6b9407a16f006bf2fbec0452eb10089a45c58 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Mon, 23 Dec 2024 12:50:20 -0800 Subject: [PATCH 11/21] Remove handling for segments --- llvm/docs/CommandGuide/llvm-objcopy.rst | 2 +- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 47 +------------ llvm/lib/ObjCopy/ELF/ELFObject.cpp | 28 -------- llvm/lib/ObjCopy/ELF/ELFObject.h | 5 -- .../tools/llvm-objcopy/ELF/remove-note.test | 70 +++---------------- 5 files changed, 12 insertions(+), 140 deletions(-) diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst index c57d367261a12..166525047d1f5 100644 --- a/llvm/docs/CommandGuide/llvm-objcopy.rst +++ b/llvm/docs/CommandGuide/llvm-objcopy.rst @@ -467,7 +467,7 @@ them. .. option:: --remove-note [/] Remove notes of integer type ```` and name ```` from SHT_NOTE - sections and PT_NOTE segments. Can be specified multiple times. + sections that are not in a segment. Can be specified multiple times. .. option:: --rename-section =[,,...] diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index e7c5cff489d94..74380bab0e446 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -623,8 +623,6 @@ struct RemoveNoteDetail { ArrayRef NotesToRemove); static std::vector updateData(ArrayRef OldData, ArrayRef ToRemove); - static Object::Section2OffsetAndSize - getSectionMapping(const Segment &Seg, ArrayRef ToRemove); }; } // namespace @@ -678,53 +676,10 @@ RemoveNoteDetail::updateData(ArrayRef OldData, return NewData; } -Object::Section2OffsetAndSize -RemoveNoteDetail::getSectionMapping(const Segment &Seg, - ArrayRef ToRemove) { - auto CalculateNewOffset = [&](uint64_t SecOffset) { - uint64_t Pos = SecOffset - Seg.Offset; - auto It = llvm::upper_bound( - ToRemove, Pos, [](const uint64_t &Pos, const DeletedRange &Range) { - return Pos < Range.OldFrom; - }); - if (It != ToRemove.begin()) { - --It; - Pos = (Pos > It->OldTo) ? (Pos - It->OldTo + It->NewPos) : It->NewPos; - } - return Pos + Seg.Offset; - }; - - // Remap the segment's sections - Object::Section2OffsetAndSize Mapping; - for (const SectionBase *Sec : Seg.Sections) { - uint64_t NewOffset = CalculateNewOffset(Sec->Offset); - uint64_t NewSize = CalculateNewOffset(Sec->Offset + Sec->Size) - NewOffset; - Mapping.try_emplace(Sec, NewOffset, NewSize); - } - return Mapping; -} - static Error removeNote(Object &Obj, endianness Endianness, ArrayRef NotesToRemove) { - for (Segment &Seg : Obj.segments()) { - // TODO: Support nested segments - if (Seg.Type != PT_NOTE || Seg.ParentSegment) - continue; - ArrayRef OldData = Seg.getContents(); - size_t Align = std::max(4, Seg.Align); - // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the - // header, so the parsers are the same. - auto ToRemove = (Endianness == endianness::little) - ? RemoveNoteDetail::findNotesToRemove( - OldData, Align, NotesToRemove) - : RemoveNoteDetail::findNotesToRemove( - OldData, Align, NotesToRemove); - if (!ToRemove.empty()) - Obj.updateSegmentData(Seg, - RemoveNoteDetail::updateData(OldData, ToRemove), - RemoveNoteDetail::getSectionMapping(Seg, ToRemove)); - } for (auto &Sec : Obj.sections()) { + // TODO: Support note sections in segments if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents()) continue; ArrayRef OldData = Sec.getContents(); diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp index 8e547fe552931..2c7a39779220e 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2319,34 +2319,6 @@ Error Object::addNewSymbolTable() { return Error::success(); } -void Object::updateSegmentData( - Segment &S, std::vector NewSegmentData, - const DenseMap> - &SectionMapping) { - // TODO: Update the parent segment - assert(!S.ParentSegment); - // TODO: Update nested segments - assert(!llvm::any_of( - Segments, [&S](const SegPtr &Seg) { return Seg->ParentSegment == &S; })); - auto It = - UpdatedSegments.insert_or_assign(&S, std::move(NewSegmentData)).first; - S.Contents = It->second; - S.FileSize = S.Contents.size(); - if (S.MemSize) - S.MemSize = S.FileSize; - assert(SectionMapping.size() == S.Sections.size()); - assert(S.Offset == S.OriginalOffset); - for (const auto &SM : SectionMapping) { - assert(SM.first->ParentSegment == &S && S.Sections.count(SM.first)); - assert(SM.second.first >= S.Offset); - assert((SM.second.first + SM.second.second) <= (S.Offset + S.FileSize)); - assert(SM.first->Offset == SM.first->OriginalOffset); - SectionBase *MutSec = const_cast(SM.first); - MutSec->OriginalOffset = MutSec->Offset = SM.second.first; - MutSec->Size = SM.second.second; - } -} - // Orders segments such that if x = y->ParentSegment then y comes before x. static void orderSegments(std::vector &Segments) { llvm::stable_sort(Segments, compareSegmentsByOffset); diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h index 285dd0bc12445..8908187673b02 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.h +++ b/llvm/lib/ObjCopy/ELF/ELFObject.h @@ -1163,7 +1163,6 @@ class Object { std::vector Segments; std::vector RemovedSections; DenseMap> UpdatedSections; - DenseMap> UpdatedSegments; static bool sectionIsAlloc(const SectionBase &Sec) { return Sec.Flags & ELF::SHF_ALLOC; @@ -1243,10 +1242,6 @@ class Object { Segments.emplace_back(std::make_unique(Data)); return *Segments.back(); } - using OffsetAndSize = std::pair; - using Section2OffsetAndSize = DenseMap; - void updateSegmentData(Segment &S, std::vector NewSegmentData, - const Section2OffsetAndSize &SectionMapping); bool isRelocatable() const { return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable; } diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index ecb39dba5ab6d..9ad873066a73e 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -23,17 +23,17 @@ # RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o # RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \ -# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=32 -D#SIZE3=32 +# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=32 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o # RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \ -# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 -D#SIZE3=24 +# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb # RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o # RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \ -# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 -D#SIZE3=24 +# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 # CHECK: Sections [ # CHECK: Section { @@ -42,43 +42,27 @@ # CHECK-NEXT: Flags [ # CHECK-NEXT: ] # CHECK-NEXT: Address: -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0:]] +# CHECK-NEXT: Offset: # CHECK-NEXT: Size: [[#%d,SIZE0]] # CHECK: Name: .note1 # CHECK-NEXT: Type: SHT_NOTE # CHECK-NEXT: Flags [ # CHECK-NEXT: ] # CHECK-NEXT: Address: -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0]] +# CHECK-NEXT: Offset: # CHECK-NEXT: Size: [[#%d,SIZE1]] # CHECK: Name: .note2 # CHECK-NEXT: Type: SHT_NOTE # CHECK-NEXT: Flags [ # CHECK-NEXT: ] # CHECK-NEXT: Address: -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]] +# CHECK-NEXT: Offset: # CHECK-NEXT: Size: 0 -# CHECK: Name: .note3 -# CHECK-NEXT: Type: SHT_NOTE -# CHECK-NEXT: Flags [ -# CHECK-NEXT: ] -# CHECK-NEXT: Address: -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET3:]] -# CHECK-NEXT: Size: [[#%d,SIZE3]] - -# CHECK: ProgramHeaders [ -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_NOTE -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0]] -# CHECK-NEXT: VirtualAddress: 0x0 -# CHECK-NEXT: PhysicalAddress: 0x0 -# CHECK-NEXT: FileSize: [[#%d,SIZE0+SIZE1]] -# CHECK-NEXT: MemSize: 0 # CHECK: NoteSections [ # CHECK-NEXT: NoteSection { # CHECK-NEXT: Name: .note0 -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0]] +# CHECK-NEXT: Offset: # CHECK-NEXT: Size: 0x[[#%X,SIZE0]] # CHECK-NEXT: Notes [ # CHECK-NEXT: { @@ -93,7 +77,7 @@ # CHECK-NEXT: } # CHECK-NEXT: NoteSection { # CHECK-NEXT: Name: .note1 -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0]] +# CHECK-NEXT: Offset: # CHECK-NEXT: Size: 0x[[#%X,SIZE1]] # CHECK-NEXT: Notes [ # CHECK-NEXT: { @@ -108,39 +92,18 @@ # CHECK-NEXT: } # CHECK-NEXT: NoteSection { # CHECK-NEXT: Name: .note2 -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]] +# CHECK-NEXT: Offset: # CHECK-NEXT: Size: 0x0 # CHECK-NEXT: Notes [ # CHECK-NEXT: ] # CHECK-NEXT: } -# CHECK-NEXT: NoteSection { -# CHECK-NEXT: Name: .note3 -# CHECK-NEXT: Offset: 0x[[#%X,OFFSET3]] -# CHECK-NEXT: Size: 0x[[#%X,SIZE3]] -# CHECK-NEXT: Notes [ -# CHECK-NEXT: { -# CHECK-NEXT: Owner: CORE -# CHECK-NEXT: Data size: 0x2 -# CHECK-NEXT: Type: NT_ARCH -# CHECK-NEXT: Description data ( -# CHECK-NEXT: 0000: 0707 -# CHECK-NEXT: ) -# CHECK-NEXT: } -# CHECK-NEXT: ] -# CHECK-NEXT: } -# CHECK-NEXT: ] --- !ELF FileHeader: Class: ELFCLASS[[ELFCLASS]] Data: ELFDATA2[[ENDIANNESS]] - Type: ET_EXEC + Type: ET_REL Machine: EM_X86_64 -ProgramHeaders: - - Type: PT_NOTE - MemSize: 0 - FirstSec: .note0 - LastSec: .note2 Sections: - Name: .note0 Type: SHT_NOTE @@ -169,17 +132,4 @@ Sections: - Name: LINUX Type: 0x01 Desc: 0505 - - Name: .note3 - Type: SHT_NOTE - AddressAlign: [[ALIGN]] - Notes: - - Name: GNU - Type: 0x01 - Desc: 0606 - - Name: CORE - Type: 0x02 - Desc: 0707 - - Name: CORE - Type: 0x03 - Desc: 0808 ... From 9baf37aea1d821671e05a96f680a9f43336573fd Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Wed, 15 Jan 2025 22:34:12 -0800 Subject: [PATCH 12/21] Remove DeletedRange.NewPos --- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 74380bab0e446..5021c55055203 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -614,7 +614,6 @@ struct RemoveNoteDetail { struct DeletedRange { uint64_t OldFrom; uint64_t OldTo; - uint64_t NewPos; }; template @@ -634,7 +633,6 @@ RemoveNoteDetail::findNotesToRemove(ArrayRef Data, size_t Align, LLVM_ELF_IMPORT_TYPES_ELFT(ELFT); std::vector ToRemove; uint64_t CurPos = 0; - uint64_t NewPos = 0; while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) { auto Nhdr = reinterpret_cast(Data.data() + CurPos); size_t FullSize = Nhdr->getSize(Align); @@ -647,9 +645,7 @@ RemoveNoteDetail::findNotesToRemove(ArrayRef Data, size_t Align, (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName()); }); if (ShouldRemove) - ToRemove.push_back({CurPos, CurPos + FullSize, NewPos}); - else - NewPos += FullSize; + ToRemove.push_back({CurPos, CurPos + FullSize}); CurPos += FullSize; } return ToRemove; @@ -666,7 +662,6 @@ RemoveNoteDetail::updateData(ArrayRef OldData, auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos); NewData.insert(NewData.end(), Slice.begin(), Slice.end()); } - assert(RemRange.NewPos == NewData.size()); CurPos = RemRange.OldTo; } if (CurPos < OldData.size()) { From 143246025bc7d593a9a3f9a3d7e58a869e654cd7 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Wed, 15 Jan 2025 22:34:46 -0800 Subject: [PATCH 13/21] "auto &RemRange" -> "const DeletedRange &RemRange" --- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 5021c55055203..49ecf9b002dc1 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -657,7 +657,7 @@ RemoveNoteDetail::updateData(ArrayRef OldData, std::vector NewData; NewData.reserve(OldData.size()); uint64_t CurPos = 0; - for (auto &RemRange : ToRemove) { + for (const DeletedRange &RemRange : ToRemove) { if (CurPos < RemRange.OldFrom) { auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos); NewData.insert(NewData.end(), Slice.begin(), Slice.end()); From a4c8edb634f00f64c8aa7cd30e599c1fa65becca Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Wed, 15 Jan 2025 22:35:42 -0800 Subject: [PATCH 14/21] Remove a blank line at the end of an namespace --- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 49ecf9b002dc1..c0a4d0ac8fee7 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -623,7 +623,6 @@ struct RemoveNoteDetail { static std::vector updateData(ArrayRef OldData, ArrayRef ToRemove); }; - } // namespace template From 56950965c937008b60c17b434f2307e8dc4e78c6 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Thu, 16 Jan 2025 13:52:47 -0800 Subject: [PATCH 15/21] Print a warning for note segments and note sections in segments --- llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h | 22 +++++--- .../include/llvm/ObjCopy/MachO/MachOObjcopy.h | 10 +++- llvm/include/llvm/ObjCopy/ObjCopy.h | 12 +++- llvm/lib/ObjCopy/Archive.cpp | 13 +++-- llvm/lib/ObjCopy/Archive.h | 4 +- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 55 ++++++++++++------- llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp | 17 +++--- llvm/lib/ObjCopy/ObjCopy.cpp | 11 ++-- .../ELF/remove-note-unsupported.test | 47 ++++++++++++++++ llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp | 22 +++++--- llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 13 +++-- llvm/unittests/ObjCopy/ObjCopyTest.cpp | 3 +- 12 files changed, 165 insertions(+), 64 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h b/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h index 552b6fb655f18..2254bb3826cf5 100644 --- a/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h +++ b/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h @@ -9,10 +9,13 @@ #ifndef LLVM_OBJCOPY_ELF_ELFOBJCOPY_H #define LLVM_OBJCOPY_ELF_ELFOBJCOPY_H +#include "llvm/ADT/STLFunctionalExtras.h" + namespace llvm { class Error; class MemoryBuffer; class raw_ostream; +class Twine; namespace object { class ELFObjectFileBase; @@ -25,26 +28,29 @@ struct ELFConfig; namespace elf { /// Apply the transformations described by \p Config and \p ELFConfig to /// \p In, which must represent an IHex file, and writes the result -/// into \p Out. +/// into \p Out. Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnIHex(const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In, - raw_ostream &Out); + raw_ostream &Out, + function_ref WarningCallback); /// Apply the transformations described by \p Config and \p ELFConfig to /// \p In, which is treated as a raw binary input, and writes the result -/// into \p Out. +/// into \p Out. Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. -Error executeObjcopyOnRawBinary(const CommonConfig &Config, - const ELFConfig &ELFConfig, MemoryBuffer &In, - raw_ostream &Out); +Error executeObjcopyOnRawBinary( + const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In, + raw_ostream &Out, function_ref WarningCallback); /// Apply the transformations described by \p Config and \p ELFConfig to -/// \p In and writes the result into \p Out. +/// \p In and writes the result into \p Out. Warnings can be printed via +/// \p WarningCallback. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnBinary(const CommonConfig &Config, const ELFConfig &ELFConfig, - object::ELFObjectFileBase &In, raw_ostream &Out); + object::ELFObjectFileBase &In, raw_ostream &Out, + function_ref WarningCallback); } // end namespace elf } // end namespace objcopy diff --git a/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h b/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h index 73690d7ace8a5..7dbb7b0a2f5af 100644 --- a/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h +++ b/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h @@ -9,9 +9,12 @@ #ifndef LLVM_OBJCOPY_MACHO_MACHOOBJCOPY_H #define LLVM_OBJCOPY_MACHO_MACHOOBJCOPY_H +#include "llvm/ADT/STLFunctionalExtras.h" + namespace llvm { class Error; class raw_ostream; +class Twine; namespace object { class MachOObjectFile; @@ -26,17 +29,20 @@ class MultiFormatConfig; namespace macho { /// Apply the transformations described by \p Config and \p MachOConfig to /// \p In and writes the result into \p Out. +/// Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnBinary(const CommonConfig &Config, const MachOConfig &MachOConfig, - object::MachOObjectFile &In, raw_ostream &Out); + object::MachOObjectFile &In, raw_ostream &Out, + function_ref WarningCallback); /// Apply the transformations described by \p Config and \p MachOConfig to /// \p In and writes the result into \p Out. +/// Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnMachOUniversalBinary( const MultiFormatConfig &Config, const object::MachOUniversalBinary &In, - raw_ostream &Out); + raw_ostream &Out, function_ref WarningCallback); } // end namespace macho } // end namespace objcopy diff --git a/llvm/include/llvm/ObjCopy/ObjCopy.h b/llvm/include/llvm/ObjCopy/ObjCopy.h index 023814002c727..76ba4949bf04c 100644 --- a/llvm/include/llvm/ObjCopy/ObjCopy.h +++ b/llvm/include/llvm/ObjCopy/ObjCopy.h @@ -9,10 +9,12 @@ #ifndef LLVM_OBJCOPY_OBJCOPY_H #define LLVM_OBJCOPY_OBJCOPY_H +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/Support/Error.h" namespace llvm { class raw_ostream; +class Twine; namespace object { class Archive; @@ -25,16 +27,20 @@ class MultiFormatConfig; /// Applies the transformations described by \p Config to /// each member in archive \p Ar. /// Writes a result in a file specified by \p Config.OutputFilename. +/// Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. -Error executeObjcopyOnArchive(const MultiFormatConfig &Config, - const object::Archive &Ar); +Error executeObjcopyOnArchive( + const MultiFormatConfig &Config, const object::Archive &Ar, + function_ref WarningCallback); /// Applies the transformations described by \p Config to \p In and writes /// the result into \p Out. This function does the dispatch based on the /// format of the input binary (COFF, ELF, MachO or wasm). +/// Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnBinary(const MultiFormatConfig &Config, - object::Binary &In, raw_ostream &Out); + object::Binary &In, raw_ostream &Out, + function_ref WarningCallback); } // end namespace objcopy } // end namespace llvm diff --git a/llvm/lib/ObjCopy/Archive.cpp b/llvm/lib/ObjCopy/Archive.cpp index a221c64edf06b..5e3882c45a0f2 100644 --- a/llvm/lib/ObjCopy/Archive.cpp +++ b/llvm/lib/ObjCopy/Archive.cpp @@ -20,7 +20,8 @@ namespace objcopy { using namespace llvm::object; Expected> -createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { +createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar, + function_ref WarningCallback) { std::vector NewArchiveMembers; Error Err = Error::success(); for (const Archive::Child &Child : Ar.children(Err)) { @@ -36,7 +37,8 @@ createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { SmallVector Buffer; raw_svector_ostream MemStream(Buffer); - if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) + if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream, + WarningCallback)) return std::move(E); Expected Member = NewArchiveMember::getOldMember( @@ -94,10 +96,11 @@ static Error deepWriteArchive(StringRef ArcName, return Error::success(); } -Error executeObjcopyOnArchive(const MultiFormatConfig &Config, - const object::Archive &Ar) { +Error executeObjcopyOnArchive( + const MultiFormatConfig &Config, const object::Archive &Ar, + function_ref WarningCallback) { Expected> NewArchiveMembersOrErr = - createNewArchiveMembers(Config, Ar); + createNewArchiveMembers(Config, Ar, WarningCallback); if (!NewArchiveMembersOrErr) return NewArchiveMembersOrErr.takeError(); const CommonConfig &CommonConfig = Config.getCommonConfig(); diff --git a/llvm/lib/ObjCopy/Archive.h b/llvm/lib/ObjCopy/Archive.h index 08aae563505ce..d9094ed0f4f53 100644 --- a/llvm/lib/ObjCopy/Archive.h +++ b/llvm/lib/ObjCopy/Archive.h @@ -20,10 +20,12 @@ class MultiFormatConfig; /// Applies the transformations described by \p Config to /// each member in archive \p Ar. +/// Warnings can be printed via \p WarningCallback. /// \returns Vector of transformed archive members. Expected> createNewArchiveMembers(const MultiFormatConfig &Config, - const object::Archive &Ar); + const object::Archive &Ar, + function_ref WarningCallback); } // end namespace objcopy } // end namespace llvm diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index c0a4d0ac8fee7..9643c14bcfdb1 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -671,11 +671,24 @@ RemoveNoteDetail::updateData(ArrayRef OldData, } static Error removeNote(Object &Obj, endianness Endianness, - ArrayRef NotesToRemove) { + ArrayRef NotesToRemove, + function_ref WarningCallback) { + // TODO: Support note segments. + for (Segment &Seg : Obj.segments()) { + if (Seg.Type == PT_NOTE) { + WarningCallback("note segments are not supported"); + break; + } + } for (auto &Sec : Obj.sections()) { - // TODO: Support note sections in segments - if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents()) + if (Sec.Type != SHT_NOTE || !Sec.hasContents()) continue; + // TODO: Support note sections in segments. + if (Sec.ParentSegment) { + WarningCallback("cannot remove note(s) from " + Sec.Name + + ": sections in segments are not supported"); + continue; + } ArrayRef OldData = Sec.getContents(); size_t Align = std::max(4, Sec.Align); // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the @@ -759,7 +772,8 @@ static Error verifyNoteSection(StringRef Name, endianness Endianness, // depend a) on the order the options occur in or b) on some opaque priority // system. The only priority is that keeps/copies overrule removes. static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, - ElfType OutputElfType, Object &Obj) { + ElfType OutputElfType, Object &Obj, + function_ref WarningCallback) { if (Config.OutputArch) { Obj.Machine = Config.OutputArch->EMachine; Obj.OSABI = Config.OutputArch->OSABI; @@ -885,7 +899,8 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, : endianness::big; if (!ELFConfig.NotesToRemove.empty()) { - if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove)) + if (Error Err = + removeNote(Obj, E, ELFConfig.NotesToRemove, WarningCallback)) return Err; } @@ -1020,9 +1035,9 @@ static Error writeOutput(const CommonConfig &Config, Object &Obj, return Writer->write(); } -Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config, - const ELFConfig &ELFConfig, - MemoryBuffer &In, raw_ostream &Out) { +Error objcopy::elf::executeObjcopyOnIHex( + const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In, + raw_ostream &Out, function_ref WarningCallback) { IHexReader Reader(&In); Expected> Obj = Reader.create(true); if (!Obj) @@ -1030,15 +1045,15 @@ Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config, const ElfType OutputElfType = getOutputElfType(Config.OutputArch.value_or(MachineInfo())); - if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) + if (Error E = + handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback)) return E; return writeOutput(Config, **Obj, Out, OutputElfType); } -Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config, - const ELFConfig &ELFConfig, - MemoryBuffer &In, - raw_ostream &Out) { +Error objcopy::elf::executeObjcopyOnRawBinary( + const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In, + raw_ostream &Out, function_ref WarningCallback) { BinaryReader Reader(&In, ELFConfig.NewSymbolVisibility); Expected> Obj = Reader.create(true); if (!Obj) @@ -1048,15 +1063,16 @@ Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config, // (-B). const ElfType OutputElfType = getOutputElfType(Config.OutputArch.value_or(MachineInfo())); - if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) + if (Error E = + handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback)) return E; return writeOutput(Config, **Obj, Out, OutputElfType); } -Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config, - const ELFConfig &ELFConfig, - object::ELFObjectFileBase &In, - raw_ostream &Out) { +Error objcopy::elf::executeObjcopyOnBinary( + const CommonConfig &Config, const ELFConfig &ELFConfig, + object::ELFObjectFileBase &In, raw_ostream &Out, + function_ref WarningCallback) { ELFReader Reader(&In, Config.ExtractPartition); Expected> Obj = Reader.create(!Config.SymbolsToAdd.empty()); @@ -1067,7 +1083,8 @@ Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config, ? getOutputElfType(*Config.OutputArch) : getOutputElfType(In); - if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) + if (Error E = + handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback)) return createFileError(Config.InputFilename, std::move(E)); if (Error E = writeOutput(Config, **Obj, Out, OutputElfType)) diff --git a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp index 91500c2d9dd47..e98a40ff3cc0e 100644 --- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp @@ -445,10 +445,10 @@ static Error handleArgs(const CommonConfig &Config, return Error::success(); } -Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config, - const MachOConfig &MachOConfig, - object::MachOObjectFile &In, - raw_ostream &Out) { +Error objcopy::macho::executeObjcopyOnBinary( + const CommonConfig &Config, const MachOConfig &MachOConfig, + object::MachOObjectFile &In, raw_ostream &Out, + function_ref WarningCallback) { MachOReader Reader(In); Expected> O = Reader.create(); if (!O) @@ -484,14 +484,14 @@ Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config, Error objcopy::macho::executeObjcopyOnMachOUniversalBinary( const MultiFormatConfig &Config, const MachOUniversalBinary &In, - raw_ostream &Out) { + raw_ostream &Out, function_ref WarningCallback) { SmallVector, 2> Binaries; SmallVector Slices; for (const auto &O : In.objects()) { Expected> ArOrErr = O.getAsArchive(); if (ArOrErr) { Expected> NewArchiveMembersOrErr = - createNewArchiveMembers(Config, **ArOrErr); + createNewArchiveMembers(Config, **ArOrErr, WarningCallback); if (!NewArchiveMembersOrErr) return NewArchiveMembersOrErr.takeError(); auto Kind = (*ArOrErr)->kind(); @@ -542,8 +542,9 @@ Error objcopy::macho::executeObjcopyOnMachOUniversalBinary( if (!MachO) return MachO.takeError(); - if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, - **ObjOrErr, MemStream)) + if (Error E = + executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, **ObjOrErr, + MemStream, WarningCallback)) return E; auto MB = std::make_unique( diff --git a/llvm/lib/ObjCopy/ObjCopy.cpp b/llvm/lib/ObjCopy/ObjCopy.cpp index 54dab11c4b192..3f8716e4fecd9 100644 --- a/llvm/lib/ObjCopy/ObjCopy.cpp +++ b/llvm/lib/ObjCopy/ObjCopy.cpp @@ -33,15 +33,16 @@ using namespace llvm::object; /// The function executeObjcopyOnBinary does the dispatch based on the format /// of the input binary (ELF, MachO or COFF). -Error executeObjcopyOnBinary(const MultiFormatConfig &Config, - object::Binary &In, raw_ostream &Out) { +Error executeObjcopyOnBinary( + const MultiFormatConfig &Config, object::Binary &In, raw_ostream &Out, + function_ref WarningCallback) { if (auto *ELFBinary = dyn_cast(&In)) { Expected ELFConfig = Config.getELFConfig(); if (!ELFConfig) return ELFConfig.takeError(); return elf::executeObjcopyOnBinary(Config.getCommonConfig(), *ELFConfig, - *ELFBinary, Out); + *ELFBinary, Out, WarningCallback); } if (auto *COFFBinary = dyn_cast(&In)) { Expected COFFConfig = Config.getCOFFConfig(); @@ -57,12 +58,12 @@ Error executeObjcopyOnBinary(const MultiFormatConfig &Config, return MachOConfig.takeError(); return macho::executeObjcopyOnBinary(Config.getCommonConfig(), *MachOConfig, - *MachOBinary, Out); + *MachOBinary, Out, WarningCallback); } if (auto *MachOUniversalBinary = dyn_cast(&In)) { return macho::executeObjcopyOnMachOUniversalBinary( - Config, *MachOUniversalBinary, Out); + Config, *MachOUniversalBinary, Out, WarningCallback); } if (auto *WasmBinary = dyn_cast(&In)) { Expected WasmConfig = Config.getWasmConfig(); diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test new file mode 100644 index 0000000000000..e664328d7aecf --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test @@ -0,0 +1,47 @@ +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT +# NOTE_SEGMENT: warning: note segments are not supported +# NOTE_SEGMENT-NOT: note segments are not supported + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_NOTE + FirstSec: .data0 + LastSec: .data0 + - Type: PT_NOTE + FirstSec: .data1 + LastSec: .data1 +Sections: + - Name: .data0 + Type: SHT_PROGBITS + AddressAlign: 4 + Content: "1122334455" + - Name: .data1 + Type: SHT_PROGBITS + AddressAlign: 4 + Content: "1122334455" + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION +# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_LOAD + FirstSec: .note + LastSec: .note +Sections: + - Name: .note + Type: SHT_NOTE + AddressAlign: 4 + Content: "1122334455" diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp index 0180abb834f9d..1c9b70f457f0d 100644 --- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp +++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp @@ -65,6 +65,10 @@ namespace dwarfutil { std::string ToolName; +static void reportWarningMsg(const Twine &Msg) { + WithColor::warning(errs(), ToolName) << Msg << '\n'; +} + static mc::RegisterMCTargetOptionsFlags MOF; static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) { @@ -261,8 +265,8 @@ static Expected saveSeparateDebugInfo(const Options &Opts, if (Error Err = writeToOutput( Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { raw_crc_ostream CRCBuffer(OutFile); - if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile, - CRCBuffer)) + if (Error Err = objcopy::executeObjcopyOnBinary( + Config, InputFile, CRCBuffer, reportWarningMsg)) return Err; WrittenFileCRC32 = CRCBuffer.getCRC32(); @@ -285,8 +289,8 @@ static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile, if (Error Err = writeToOutput( Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { - if (Error Err = - objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile)) + if (Error Err = objcopy::executeObjcopyOnBinary( + Config, InputFile, OutFile, reportWarningMsg)) return Err; return Error::success(); @@ -373,8 +377,8 @@ saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile, Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { raw_crc_ostream CRCBuffer(OutFile); - if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile, - CRCBuffer)) + if (Error Err = objcopy::executeObjcopyOnBinary( + Config, InputFile, CRCBuffer, reportWarningMsg)) return Err; WrittenFileCRC32 = CRCBuffer.getCRC32(); @@ -399,7 +403,8 @@ static Error saveSingleLinkedDebugInfo(const Options &Opts, if (Error Err = writeToOutput( Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { - return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile); + return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile, + reportWarningMsg); })) return Err; @@ -435,7 +440,8 @@ static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) { if (Error Err = writeToOutput( Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { - return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile); + return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile, + reportWarningMsg); })) return Err; diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index ad3e60472369b..71f3f2233ae07 100644 --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -71,6 +71,10 @@ static ErrorSuccess reportWarning(Error E) { return Error::success(); } +static void reportWarningMsg(const Twine &Msg) { + WithColor::warning(errs(), ToolName) << Msg << '\n'; +} + static Expected getDriverConfig(ArrayRef Args) { StringRef Stem = sys::path::stem(ToolName); auto Is = [=](StringRef Tool) { @@ -105,7 +109,7 @@ static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In, return ELFConfig.takeError(); return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In, - Out); + Out, reportWarningMsg); } /// The function executeObjcopyOnRawBinary does the dispatch based on the format @@ -126,7 +130,8 @@ static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr, if (!ELFConfig) return ELFConfig.takeError(); - return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out); + return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out, + reportWarningMsg); } llvm_unreachable("unsupported output format"); @@ -176,13 +181,13 @@ static Error executeObjcopy(ConfigManager &ConfigMgr) { if (Archive *Ar = dyn_cast(BinaryHolder.getBinary())) { // Handle Archive. - if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar)) + if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar, reportWarningMsg)) return E; } else { // Handle llvm::object::Binary. ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(), - OutFile); + OutFile, reportWarningMsg); }; } } diff --git a/llvm/unittests/ObjCopy/ObjCopyTest.cpp b/llvm/unittests/ObjCopy/ObjCopyTest.cpp index 4382c73e889e9..244280047a8cc 100644 --- a/llvm/unittests/ObjCopy/ObjCopyTest.cpp +++ b/llvm/unittests/ObjCopy/ObjCopyTest.cpp @@ -125,7 +125,8 @@ callObjCopy(ConfigManager &Config, object::Binary &In, function_ref IsValidFormat) { raw_svector_ostream OutStream(DataVector); - if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream)) + if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream, + [](const Twine &) {})) return std::move(Err); MemoryBufferRef Buffer(StringRef(DataVector.data(), DataVector.size()), From 17a3c7719412924caabad3b4ce4cf9f8699ef087 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Thu, 16 Jan 2025 18:16:52 -0800 Subject: [PATCH 16/21] Extend the test --- .../tools/llvm-objcopy/ELF/remove-note.test | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index 9ad873066a73e..06762892e0de5 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -1,4 +1,4 @@ -## Check incompatible options +## Check incompatible options. # RUN: not llvm-objcopy --remove-note=1 --remove-section=.test - 2>&1 | FileCheck %s --check-prefix=ERR-REMSEC # RUN: not llvm-objcopy --remove-note=1 --add-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-ADDSEC # RUN: not llvm-objcopy --remove-note=1 --update-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-UPDSEC @@ -7,7 +7,7 @@ # ERR-ADDSEC: error: cannot specify both --remove-note and --add-section # ERR-UPDSEC: error: cannot specify both --remove-note and --update-section -## Check invalid argument formats +## Check invalid argument formats. # RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID # RUN: not llvm-objcopy --remove-note=CORE/ - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID # RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME @@ -20,20 +20,24 @@ # ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2' # ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber' +## Check deleting notes: +## * --remove-note=1 will remove note "CORE/1" and "LINUX/1", +## * --remove-note=DUMMY/2 will not remove any notes because there are no notes with this owner, +## * --remove-note=CORE/3 will remove "CORE/3" but preserve "LINUX/3". # RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o # RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \ -# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=32 +# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=64 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o # RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \ -# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 +# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=48 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb # RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o # RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \ -# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24 +# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=48 # CHECK: Sections [ # CHECK: Section { @@ -70,7 +74,7 @@ # CHECK-NEXT: Data size: 0x2 # CHECK-NEXT: Type: NT_ARCH # CHECK-NEXT: Description data ( -# CHECK-NEXT: 0000: 0202 +# CHECK-NEXT: 0000: 0201 # CHECK-NEXT: ) # CHECK-NEXT: } # CHECK-NEXT: ] @@ -81,11 +85,19 @@ # CHECK-NEXT: Size: 0x[[#%X,SIZE1]] # CHECK-NEXT: Notes [ # CHECK-NEXT: { +# CHECK-NEXT: Owner: LINUX +# CHECK-NEXT: Data size: 0x2 +# CHECK-NEXT: Type: Unknown (0x00000003) +# CHECK-NEXT: Description data ( +# CHECK-NEXT: 0000: 0301 +# CHECK-NEXT: ) +# CHECK-NEXT: } +# CHECK-NEXT: { # CHECK-NEXT: Owner: CORE # CHECK-NEXT: Data size: 0x2 # CHECK-NEXT: Type: Unknown (0x00000004) # CHECK-NEXT: Description data ( -# CHECK-NEXT: 0000: 0404 +# CHECK-NEXT: 0000: 0401 # CHECK-NEXT: ) # CHECK-NEXT: } # CHECK-NEXT: ] @@ -114,22 +126,25 @@ Sections: Desc: 0101 - Name: CORE Type: 0x02 - Desc: 0202 + Desc: 0201 - Name: .note1 Type: SHT_NOTE AddressAlign: [[ALIGN]] Notes: + - Name: LINUX + Type: 0x03 + Desc: 0301 - Name: CORE Type: 0x03 - Desc: 0303 + Desc: 0302 - Name: CORE Type: 0x04 - Desc: 0404 + Desc: 0401 - Name: .note2 Type: SHT_NOTE AddressAlign: [[ALIGN]] Notes: - Name: LINUX Type: 0x01 - Desc: 0505 + Desc: 0102 ... From 08f7f2378ca2d3578ea287b6774e3037ebbcd4c6 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 17 Jan 2025 17:01:30 -0800 Subject: [PATCH 17/21] Revert "Print a warning for note segments and note sections in segments" This reverts commit 56950965c937008b60c17b434f2307e8dc4e78c6. --- llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h | 22 +++----- .../include/llvm/ObjCopy/MachO/MachOObjcopy.h | 10 +--- llvm/include/llvm/ObjCopy/ObjCopy.h | 12 +--- llvm/lib/ObjCopy/Archive.cpp | 13 ++--- llvm/lib/ObjCopy/Archive.h | 4 +- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 55 +++++++------------ llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp | 17 +++--- llvm/lib/ObjCopy/ObjCopy.cpp | 11 ++-- .../ELF/remove-note-unsupported.test | 47 ---------------- llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp | 22 +++----- llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 13 ++--- llvm/unittests/ObjCopy/ObjCopyTest.cpp | 3 +- 12 files changed, 64 insertions(+), 165 deletions(-) delete mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h b/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h index 2254bb3826cf5..552b6fb655f18 100644 --- a/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h +++ b/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h @@ -9,13 +9,10 @@ #ifndef LLVM_OBJCOPY_ELF_ELFOBJCOPY_H #define LLVM_OBJCOPY_ELF_ELFOBJCOPY_H -#include "llvm/ADT/STLFunctionalExtras.h" - namespace llvm { class Error; class MemoryBuffer; class raw_ostream; -class Twine; namespace object { class ELFObjectFileBase; @@ -28,29 +25,26 @@ struct ELFConfig; namespace elf { /// Apply the transformations described by \p Config and \p ELFConfig to /// \p In, which must represent an IHex file, and writes the result -/// into \p Out. Warnings can be printed via \p WarningCallback. +/// into \p Out. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnIHex(const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In, - raw_ostream &Out, - function_ref WarningCallback); + raw_ostream &Out); /// Apply the transformations described by \p Config and \p ELFConfig to /// \p In, which is treated as a raw binary input, and writes the result -/// into \p Out. Warnings can be printed via \p WarningCallback. +/// into \p Out. /// \returns any Error encountered whilst performing the operation. -Error executeObjcopyOnRawBinary( - const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In, - raw_ostream &Out, function_ref WarningCallback); +Error executeObjcopyOnRawBinary(const CommonConfig &Config, + const ELFConfig &ELFConfig, MemoryBuffer &In, + raw_ostream &Out); /// Apply the transformations described by \p Config and \p ELFConfig to -/// \p In and writes the result into \p Out. Warnings can be printed via -/// \p WarningCallback. +/// \p In and writes the result into \p Out. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnBinary(const CommonConfig &Config, const ELFConfig &ELFConfig, - object::ELFObjectFileBase &In, raw_ostream &Out, - function_ref WarningCallback); + object::ELFObjectFileBase &In, raw_ostream &Out); } // end namespace elf } // end namespace objcopy diff --git a/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h b/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h index 7dbb7b0a2f5af..73690d7ace8a5 100644 --- a/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h +++ b/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h @@ -9,12 +9,9 @@ #ifndef LLVM_OBJCOPY_MACHO_MACHOOBJCOPY_H #define LLVM_OBJCOPY_MACHO_MACHOOBJCOPY_H -#include "llvm/ADT/STLFunctionalExtras.h" - namespace llvm { class Error; class raw_ostream; -class Twine; namespace object { class MachOObjectFile; @@ -29,20 +26,17 @@ class MultiFormatConfig; namespace macho { /// Apply the transformations described by \p Config and \p MachOConfig to /// \p In and writes the result into \p Out. -/// Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnBinary(const CommonConfig &Config, const MachOConfig &MachOConfig, - object::MachOObjectFile &In, raw_ostream &Out, - function_ref WarningCallback); + object::MachOObjectFile &In, raw_ostream &Out); /// Apply the transformations described by \p Config and \p MachOConfig to /// \p In and writes the result into \p Out. -/// Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnMachOUniversalBinary( const MultiFormatConfig &Config, const object::MachOUniversalBinary &In, - raw_ostream &Out, function_ref WarningCallback); + raw_ostream &Out); } // end namespace macho } // end namespace objcopy diff --git a/llvm/include/llvm/ObjCopy/ObjCopy.h b/llvm/include/llvm/ObjCopy/ObjCopy.h index 76ba4949bf04c..023814002c727 100644 --- a/llvm/include/llvm/ObjCopy/ObjCopy.h +++ b/llvm/include/llvm/ObjCopy/ObjCopy.h @@ -9,12 +9,10 @@ #ifndef LLVM_OBJCOPY_OBJCOPY_H #define LLVM_OBJCOPY_OBJCOPY_H -#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/Support/Error.h" namespace llvm { class raw_ostream; -class Twine; namespace object { class Archive; @@ -27,20 +25,16 @@ class MultiFormatConfig; /// Applies the transformations described by \p Config to /// each member in archive \p Ar. /// Writes a result in a file specified by \p Config.OutputFilename. -/// Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. -Error executeObjcopyOnArchive( - const MultiFormatConfig &Config, const object::Archive &Ar, - function_ref WarningCallback); +Error executeObjcopyOnArchive(const MultiFormatConfig &Config, + const object::Archive &Ar); /// Applies the transformations described by \p Config to \p In and writes /// the result into \p Out. This function does the dispatch based on the /// format of the input binary (COFF, ELF, MachO or wasm). -/// Warnings can be printed via \p WarningCallback. /// \returns any Error encountered whilst performing the operation. Error executeObjcopyOnBinary(const MultiFormatConfig &Config, - object::Binary &In, raw_ostream &Out, - function_ref WarningCallback); + object::Binary &In, raw_ostream &Out); } // end namespace objcopy } // end namespace llvm diff --git a/llvm/lib/ObjCopy/Archive.cpp b/llvm/lib/ObjCopy/Archive.cpp index 5e3882c45a0f2..a221c64edf06b 100644 --- a/llvm/lib/ObjCopy/Archive.cpp +++ b/llvm/lib/ObjCopy/Archive.cpp @@ -20,8 +20,7 @@ namespace objcopy { using namespace llvm::object; Expected> -createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar, - function_ref WarningCallback) { +createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { std::vector NewArchiveMembers; Error Err = Error::success(); for (const Archive::Child &Child : Ar.children(Err)) { @@ -37,8 +36,7 @@ createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar, SmallVector Buffer; raw_svector_ostream MemStream(Buffer); - if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream, - WarningCallback)) + if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) return std::move(E); Expected Member = NewArchiveMember::getOldMember( @@ -96,11 +94,10 @@ static Error deepWriteArchive(StringRef ArcName, return Error::success(); } -Error executeObjcopyOnArchive( - const MultiFormatConfig &Config, const object::Archive &Ar, - function_ref WarningCallback) { +Error executeObjcopyOnArchive(const MultiFormatConfig &Config, + const object::Archive &Ar) { Expected> NewArchiveMembersOrErr = - createNewArchiveMembers(Config, Ar, WarningCallback); + createNewArchiveMembers(Config, Ar); if (!NewArchiveMembersOrErr) return NewArchiveMembersOrErr.takeError(); const CommonConfig &CommonConfig = Config.getCommonConfig(); diff --git a/llvm/lib/ObjCopy/Archive.h b/llvm/lib/ObjCopy/Archive.h index d9094ed0f4f53..08aae563505ce 100644 --- a/llvm/lib/ObjCopy/Archive.h +++ b/llvm/lib/ObjCopy/Archive.h @@ -20,12 +20,10 @@ class MultiFormatConfig; /// Applies the transformations described by \p Config to /// each member in archive \p Ar. -/// Warnings can be printed via \p WarningCallback. /// \returns Vector of transformed archive members. Expected> createNewArchiveMembers(const MultiFormatConfig &Config, - const object::Archive &Ar, - function_ref WarningCallback); + const object::Archive &Ar); } // end namespace objcopy } // end namespace llvm diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 9643c14bcfdb1..c0a4d0ac8fee7 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -671,24 +671,11 @@ RemoveNoteDetail::updateData(ArrayRef OldData, } static Error removeNote(Object &Obj, endianness Endianness, - ArrayRef NotesToRemove, - function_ref WarningCallback) { - // TODO: Support note segments. - for (Segment &Seg : Obj.segments()) { - if (Seg.Type == PT_NOTE) { - WarningCallback("note segments are not supported"); - break; - } - } + ArrayRef NotesToRemove) { for (auto &Sec : Obj.sections()) { - if (Sec.Type != SHT_NOTE || !Sec.hasContents()) + // TODO: Support note sections in segments + if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents()) continue; - // TODO: Support note sections in segments. - if (Sec.ParentSegment) { - WarningCallback("cannot remove note(s) from " + Sec.Name + - ": sections in segments are not supported"); - continue; - } ArrayRef OldData = Sec.getContents(); size_t Align = std::max(4, Sec.Align); // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the @@ -772,8 +759,7 @@ static Error verifyNoteSection(StringRef Name, endianness Endianness, // depend a) on the order the options occur in or b) on some opaque priority // system. The only priority is that keeps/copies overrule removes. static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, - ElfType OutputElfType, Object &Obj, - function_ref WarningCallback) { + ElfType OutputElfType, Object &Obj) { if (Config.OutputArch) { Obj.Machine = Config.OutputArch->EMachine; Obj.OSABI = Config.OutputArch->OSABI; @@ -899,8 +885,7 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, : endianness::big; if (!ELFConfig.NotesToRemove.empty()) { - if (Error Err = - removeNote(Obj, E, ELFConfig.NotesToRemove, WarningCallback)) + if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove)) return Err; } @@ -1035,9 +1020,9 @@ static Error writeOutput(const CommonConfig &Config, Object &Obj, return Writer->write(); } -Error objcopy::elf::executeObjcopyOnIHex( - const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In, - raw_ostream &Out, function_ref WarningCallback) { +Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config, + const ELFConfig &ELFConfig, + MemoryBuffer &In, raw_ostream &Out) { IHexReader Reader(&In); Expected> Obj = Reader.create(true); if (!Obj) @@ -1045,15 +1030,15 @@ Error objcopy::elf::executeObjcopyOnIHex( const ElfType OutputElfType = getOutputElfType(Config.OutputArch.value_or(MachineInfo())); - if (Error E = - handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback)) + if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) return E; return writeOutput(Config, **Obj, Out, OutputElfType); } -Error objcopy::elf::executeObjcopyOnRawBinary( - const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In, - raw_ostream &Out, function_ref WarningCallback) { +Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config, + const ELFConfig &ELFConfig, + MemoryBuffer &In, + raw_ostream &Out) { BinaryReader Reader(&In, ELFConfig.NewSymbolVisibility); Expected> Obj = Reader.create(true); if (!Obj) @@ -1063,16 +1048,15 @@ Error objcopy::elf::executeObjcopyOnRawBinary( // (-B). const ElfType OutputElfType = getOutputElfType(Config.OutputArch.value_or(MachineInfo())); - if (Error E = - handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback)) + if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) return E; return writeOutput(Config, **Obj, Out, OutputElfType); } -Error objcopy::elf::executeObjcopyOnBinary( - const CommonConfig &Config, const ELFConfig &ELFConfig, - object::ELFObjectFileBase &In, raw_ostream &Out, - function_ref WarningCallback) { +Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config, + const ELFConfig &ELFConfig, + object::ELFObjectFileBase &In, + raw_ostream &Out) { ELFReader Reader(&In, Config.ExtractPartition); Expected> Obj = Reader.create(!Config.SymbolsToAdd.empty()); @@ -1083,8 +1067,7 @@ Error objcopy::elf::executeObjcopyOnBinary( ? getOutputElfType(*Config.OutputArch) : getOutputElfType(In); - if (Error E = - handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback)) + if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) return createFileError(Config.InputFilename, std::move(E)); if (Error E = writeOutput(Config, **Obj, Out, OutputElfType)) diff --git a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp index e98a40ff3cc0e..91500c2d9dd47 100644 --- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp @@ -445,10 +445,10 @@ static Error handleArgs(const CommonConfig &Config, return Error::success(); } -Error objcopy::macho::executeObjcopyOnBinary( - const CommonConfig &Config, const MachOConfig &MachOConfig, - object::MachOObjectFile &In, raw_ostream &Out, - function_ref WarningCallback) { +Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config, + const MachOConfig &MachOConfig, + object::MachOObjectFile &In, + raw_ostream &Out) { MachOReader Reader(In); Expected> O = Reader.create(); if (!O) @@ -484,14 +484,14 @@ Error objcopy::macho::executeObjcopyOnBinary( Error objcopy::macho::executeObjcopyOnMachOUniversalBinary( const MultiFormatConfig &Config, const MachOUniversalBinary &In, - raw_ostream &Out, function_ref WarningCallback) { + raw_ostream &Out) { SmallVector, 2> Binaries; SmallVector Slices; for (const auto &O : In.objects()) { Expected> ArOrErr = O.getAsArchive(); if (ArOrErr) { Expected> NewArchiveMembersOrErr = - createNewArchiveMembers(Config, **ArOrErr, WarningCallback); + createNewArchiveMembers(Config, **ArOrErr); if (!NewArchiveMembersOrErr) return NewArchiveMembersOrErr.takeError(); auto Kind = (*ArOrErr)->kind(); @@ -542,9 +542,8 @@ Error objcopy::macho::executeObjcopyOnMachOUniversalBinary( if (!MachO) return MachO.takeError(); - if (Error E = - executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, **ObjOrErr, - MemStream, WarningCallback)) + if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, + **ObjOrErr, MemStream)) return E; auto MB = std::make_unique( diff --git a/llvm/lib/ObjCopy/ObjCopy.cpp b/llvm/lib/ObjCopy/ObjCopy.cpp index 3f8716e4fecd9..54dab11c4b192 100644 --- a/llvm/lib/ObjCopy/ObjCopy.cpp +++ b/llvm/lib/ObjCopy/ObjCopy.cpp @@ -33,16 +33,15 @@ using namespace llvm::object; /// The function executeObjcopyOnBinary does the dispatch based on the format /// of the input binary (ELF, MachO or COFF). -Error executeObjcopyOnBinary( - const MultiFormatConfig &Config, object::Binary &In, raw_ostream &Out, - function_ref WarningCallback) { +Error executeObjcopyOnBinary(const MultiFormatConfig &Config, + object::Binary &In, raw_ostream &Out) { if (auto *ELFBinary = dyn_cast(&In)) { Expected ELFConfig = Config.getELFConfig(); if (!ELFConfig) return ELFConfig.takeError(); return elf::executeObjcopyOnBinary(Config.getCommonConfig(), *ELFConfig, - *ELFBinary, Out, WarningCallback); + *ELFBinary, Out); } if (auto *COFFBinary = dyn_cast(&In)) { Expected COFFConfig = Config.getCOFFConfig(); @@ -58,12 +57,12 @@ Error executeObjcopyOnBinary( return MachOConfig.takeError(); return macho::executeObjcopyOnBinary(Config.getCommonConfig(), *MachOConfig, - *MachOBinary, Out, WarningCallback); + *MachOBinary, Out); } if (auto *MachOUniversalBinary = dyn_cast(&In)) { return macho::executeObjcopyOnMachOUniversalBinary( - Config, *MachOUniversalBinary, Out, WarningCallback); + Config, *MachOUniversalBinary, Out); } if (auto *WasmBinary = dyn_cast(&In)) { Expected WasmConfig = Config.getWasmConfig(); diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test deleted file mode 100644 index e664328d7aecf..0000000000000 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test +++ /dev/null @@ -1,47 +0,0 @@ -# RUN: yaml2obj --docnum=1 %s -o %t1 -# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT -# NOTE_SEGMENT: warning: note segments are not supported -# NOTE_SEGMENT-NOT: note segments are not supported - ---- !ELF -FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_EXEC - Machine: EM_X86_64 -ProgramHeaders: - - Type: PT_NOTE - FirstSec: .data0 - LastSec: .data0 - - Type: PT_NOTE - FirstSec: .data1 - LastSec: .data1 -Sections: - - Name: .data0 - Type: SHT_PROGBITS - AddressAlign: 4 - Content: "1122334455" - - Name: .data1 - Type: SHT_PROGBITS - AddressAlign: 4 - Content: "1122334455" - -# RUN: yaml2obj --docnum=2 %s -o %t2 -# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION -# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported - ---- !ELF -FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_EXEC - Machine: EM_X86_64 -ProgramHeaders: - - Type: PT_LOAD - FirstSec: .note - LastSec: .note -Sections: - - Name: .note - Type: SHT_NOTE - AddressAlign: 4 - Content: "1122334455" diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp index 1c9b70f457f0d..0180abb834f9d 100644 --- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp +++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp @@ -65,10 +65,6 @@ namespace dwarfutil { std::string ToolName; -static void reportWarningMsg(const Twine &Msg) { - WithColor::warning(errs(), ToolName) << Msg << '\n'; -} - static mc::RegisterMCTargetOptionsFlags MOF; static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) { @@ -265,8 +261,8 @@ static Expected saveSeparateDebugInfo(const Options &Opts, if (Error Err = writeToOutput( Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { raw_crc_ostream CRCBuffer(OutFile); - if (Error Err = objcopy::executeObjcopyOnBinary( - Config, InputFile, CRCBuffer, reportWarningMsg)) + if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile, + CRCBuffer)) return Err; WrittenFileCRC32 = CRCBuffer.getCRC32(); @@ -289,8 +285,8 @@ static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile, if (Error Err = writeToOutput( Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { - if (Error Err = objcopy::executeObjcopyOnBinary( - Config, InputFile, OutFile, reportWarningMsg)) + if (Error Err = + objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile)) return Err; return Error::success(); @@ -377,8 +373,8 @@ saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile, Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { raw_crc_ostream CRCBuffer(OutFile); - if (Error Err = objcopy::executeObjcopyOnBinary( - Config, InputFile, CRCBuffer, reportWarningMsg)) + if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile, + CRCBuffer)) return Err; WrittenFileCRC32 = CRCBuffer.getCRC32(); @@ -403,8 +399,7 @@ static Error saveSingleLinkedDebugInfo(const Options &Opts, if (Error Err = writeToOutput( Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { - return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile, - reportWarningMsg); + return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile); })) return Err; @@ -440,8 +435,7 @@ static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) { if (Error Err = writeToOutput( Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { - return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile, - reportWarningMsg); + return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile); })) return Err; diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index 71f3f2233ae07..ad3e60472369b 100644 --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -71,10 +71,6 @@ static ErrorSuccess reportWarning(Error E) { return Error::success(); } -static void reportWarningMsg(const Twine &Msg) { - WithColor::warning(errs(), ToolName) << Msg << '\n'; -} - static Expected getDriverConfig(ArrayRef Args) { StringRef Stem = sys::path::stem(ToolName); auto Is = [=](StringRef Tool) { @@ -109,7 +105,7 @@ static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In, return ELFConfig.takeError(); return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In, - Out, reportWarningMsg); + Out); } /// The function executeObjcopyOnRawBinary does the dispatch based on the format @@ -130,8 +126,7 @@ static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr, if (!ELFConfig) return ELFConfig.takeError(); - return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out, - reportWarningMsg); + return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out); } llvm_unreachable("unsupported output format"); @@ -181,13 +176,13 @@ static Error executeObjcopy(ConfigManager &ConfigMgr) { if (Archive *Ar = dyn_cast(BinaryHolder.getBinary())) { // Handle Archive. - if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar, reportWarningMsg)) + if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar)) return E; } else { // Handle llvm::object::Binary. ObjcopyFunc = [&](raw_ostream &OutFile) -> Error { return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(), - OutFile, reportWarningMsg); + OutFile); }; } } diff --git a/llvm/unittests/ObjCopy/ObjCopyTest.cpp b/llvm/unittests/ObjCopy/ObjCopyTest.cpp index 244280047a8cc..4382c73e889e9 100644 --- a/llvm/unittests/ObjCopy/ObjCopyTest.cpp +++ b/llvm/unittests/ObjCopy/ObjCopyTest.cpp @@ -125,8 +125,7 @@ callObjCopy(ConfigManager &Config, object::Binary &In, function_ref IsValidFormat) { raw_svector_ostream OutStream(DataVector); - if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream, - [](const Twine &) {})) + if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream)) return std::move(Err); MemoryBufferRef Buffer(StringRef(DataVector.data(), DataVector.size()), From 1ee4850bbb6d35c9327e4bc0eb5c5a17a2b69422 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 17 Jan 2025 17:02:13 -0800 Subject: [PATCH 18/21] removeNote() -> removeNotes() --- llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index c0a4d0ac8fee7..7c6e957c86e47 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -670,8 +670,8 @@ RemoveNoteDetail::updateData(ArrayRef OldData, return NewData; } -static Error removeNote(Object &Obj, endianness Endianness, - ArrayRef NotesToRemove) { +static Error removeNotes(Object &Obj, endianness Endianness, + ArrayRef NotesToRemove) { for (auto &Sec : Obj.sections()) { // TODO: Support note sections in segments if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents()) @@ -885,7 +885,7 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, : endianness::big; if (!ELFConfig.NotesToRemove.empty()) { - if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove)) + if (Error Err = removeNotes(Obj, E, ELFConfig.NotesToRemove)) return Err; } From 2860c31aac25dd5afdb2fde14574e3eebde22a75 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 17 Jan 2025 20:13:19 -0800 Subject: [PATCH 19/21] Print a warning for note segments and note sections in segments v2 --- llvm/include/llvm/ObjCopy/CommonConfig.h | 5 ++ llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 30 ++++++++++-- .../ELF/remove-note-unsupported.test | 47 +++++++++++++++++++ llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 2 + 4 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h index 5ae09760e9a54..aea9cd6f9a9c7 100644 --- a/llvm/include/llvm/ObjCopy/CommonConfig.h +++ b/llvm/include/llvm/ObjCopy/CommonConfig.h @@ -281,6 +281,11 @@ struct CommonConfig { SmallVector, 0> compressSections; + + // ErrorCallback is used to handle recoverable errors. An Error returned + // by the callback aborts the execution and is then returned to the caller. + // If the callback is not set, the errors are not issued. + std::function ErrorCallback; }; } // namespace objcopy diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 7c6e957c86e47..42581af387d8d 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -671,11 +671,32 @@ RemoveNoteDetail::updateData(ArrayRef OldData, } static Error removeNotes(Object &Obj, endianness Endianness, - ArrayRef NotesToRemove) { + ArrayRef NotesToRemove, + function_ref ErrorCallback) { + // TODO: Support note segments. + if (ErrorCallback) { + for (Segment &Seg : Obj.segments()) { + if (Seg.Type == PT_NOTE) { + if (Error E = ErrorCallback(createStringError( + errc::not_supported, "note segments are not supported"))) + return E; + break; + } + } + } for (auto &Sec : Obj.sections()) { - // TODO: Support note sections in segments - if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents()) + if (Sec.Type != SHT_NOTE || !Sec.hasContents()) + continue; + // TODO: Support note sections in segments. + if (Sec.ParentSegment) { + if (ErrorCallback) + if (Error E = ErrorCallback(createStringError( + errc::not_supported, + "cannot remove note(s) from " + Sec.Name + + ": sections in segments are not supported"))) + return E; continue; + } ArrayRef OldData = Sec.getContents(); size_t Align = std::max(4, Sec.Align); // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the @@ -885,7 +906,8 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, : endianness::big; if (!ELFConfig.NotesToRemove.empty()) { - if (Error Err = removeNotes(Obj, E, ELFConfig.NotesToRemove)) + if (Error Err = + removeNotes(Obj, E, ELFConfig.NotesToRemove, Config.ErrorCallback)) return Err; } diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test new file mode 100644 index 0000000000000..e664328d7aecf --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test @@ -0,0 +1,47 @@ +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT +# NOTE_SEGMENT: warning: note segments are not supported +# NOTE_SEGMENT-NOT: note segments are not supported + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_NOTE + FirstSec: .data0 + LastSec: .data0 + - Type: PT_NOTE + FirstSec: .data1 + LastSec: .data1 +Sections: + - Name: .data0 + Type: SHT_PROGBITS + AddressAlign: 4 + Content: "1122334455" + - Name: .data1 + Type: SHT_PROGBITS + AddressAlign: 4 + Content: "1122334455" + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION +# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_LOAD + FirstSec: .note + LastSec: .note +Sections: + - Name: .note + Type: SHT_NOTE + AddressAlign: 4 + Content: "1122334455" diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index ad3e60472369b..7e708e309f207 100644 --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -248,6 +248,8 @@ int llvm_objcopy_main(int argc, char **argv, const llvm::ToolContext &) { return 1; } for (ConfigManager &ConfigMgr : DriverConfig->CopyConfigs) { + assert(!ConfigMgr.Common.ErrorCallback); + ConfigMgr.Common.ErrorCallback = reportWarning; if (Error E = executeObjcopy(ConfigMgr)) { logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); return 1; From b1957e7c706ab631b4a77211b75735dbe69cd564 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 17 Jan 2025 20:23:55 -0800 Subject: [PATCH 20/21] std::vector::iterator -> SecPtr& --- llvm/lib/ObjCopy/ELF/ELFObject.cpp | 24 +++++++++++------------- llvm/lib/ObjCopy/ELF/ELFObject.h | 3 +-- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp index 2c7a39779220e..45c7ea49b5d93 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2154,27 +2154,25 @@ ELFWriter::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH, : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), OnlyKeepDebug(OnlyKeepDebug) {} -Error Object::updateSectionData(std::vector::iterator It, - ArrayRef Data) { - auto *OldSec = It->get(); - if (!OldSec->hasContents()) +Error Object::updateSectionData(SecPtr &Sec, ArrayRef Data) { + if (!Sec->hasContents()) return createStringError( errc::invalid_argument, "section '%s' cannot be updated because it does not have contents", - OldSec->Name.c_str()); + Sec->Name.c_str()); - if (Data.size() > OldSec->Size && OldSec->ParentSegment) + if (Data.size() > Sec->Size && Sec->ParentSegment) return createStringError(errc::invalid_argument, "cannot fit data of size %zu into section '%s' " "with size %" PRIu64 " that is part of a segment", - Data.size(), OldSec->Name.c_str(), OldSec->Size); + Data.size(), Sec->Name.c_str(), Sec->Size); - if (!OldSec->ParentSegment) { - *It = std::make_unique(*OldSec, Data); + if (!Sec->ParentSegment) { + Sec = std::make_unique(*Sec, Data); } else { // The segment writer will be in charge of updating these contents. - OldSec->Size = Data.size(); - UpdatedSections[OldSec] = Data; + Sec->Size = Data.size(); + UpdatedSections[Sec.get()] = Data; } return Error::success(); @@ -2186,14 +2184,14 @@ Error Object::updateSection(StringRef Name, ArrayRef Data) { if (It == Sections.end()) return createStringError(errc::invalid_argument, "section '%s' not found", Name.str().c_str()); - return updateSectionData(It, Data); + return updateSectionData(*It, Data); } Error Object::updateSectionData(SectionBase &S, ArrayRef Data) { auto It = llvm::find_if(Sections, [&](const SecPtr &Sec) { return Sec.get() == &S; }); assert(It != Sections.end() && "The section should belong to the object"); - return updateSectionData(It, Data); + return updateSectionData(*It, Data); } Error Object::removeSections( diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h index 8908187673b02..d8f79a4b1a3cc 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.h +++ b/llvm/lib/ObjCopy/ELF/ELFObject.h @@ -1168,8 +1168,7 @@ class Object { return Sec.Flags & ELF::SHF_ALLOC; }; - Error updateSectionData(std::vector::iterator SecIt, - ArrayRef Data); + Error updateSectionData(SecPtr &Sec, ArrayRef Data); public: template From 9110b2ca3fc291d790bdcd434a5a6f04ce491afa Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Wed, 22 Jan 2025 20:21:14 -0800 Subject: [PATCH 21/21] Move tests from 'remove-note-unsupported.test' to 'remove-note.test' --- .../ELF/remove-note-unsupported.test | 47 ---------------- .../tools/llvm-objcopy/ELF/remove-note.test | 56 +++++++++++++++++-- 2 files changed, 52 insertions(+), 51 deletions(-) delete mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test deleted file mode 100644 index e664328d7aecf..0000000000000 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test +++ /dev/null @@ -1,47 +0,0 @@ -# RUN: yaml2obj --docnum=1 %s -o %t1 -# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT -# NOTE_SEGMENT: warning: note segments are not supported -# NOTE_SEGMENT-NOT: note segments are not supported - ---- !ELF -FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_EXEC - Machine: EM_X86_64 -ProgramHeaders: - - Type: PT_NOTE - FirstSec: .data0 - LastSec: .data0 - - Type: PT_NOTE - FirstSec: .data1 - LastSec: .data1 -Sections: - - Name: .data0 - Type: SHT_PROGBITS - AddressAlign: 4 - Content: "1122334455" - - Name: .data1 - Type: SHT_PROGBITS - AddressAlign: 4 - Content: "1122334455" - -# RUN: yaml2obj --docnum=2 %s -o %t2 -# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION -# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported - ---- !ELF -FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_EXEC - Machine: EM_X86_64 -ProgramHeaders: - - Type: PT_LOAD - FirstSec: .note - LastSec: .note -Sections: - - Name: .note - Type: SHT_NOTE - AddressAlign: 4 - Content: "1122334455" diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test index 06762892e0de5..f8936bf9ea731 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test @@ -24,17 +24,17 @@ ## * --remove-note=1 will remove note "CORE/1" and "LINUX/1", ## * --remove-note=DUMMY/2 will not remove any notes because there are no notes with this owner, ## * --remove-note=CORE/3 will remove "CORE/3" but preserve "LINUX/3". -# RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb +# RUN: yaml2obj --docnum=1 -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o # RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \ # RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=64 -# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb +# RUN: yaml2obj --docnum=1 -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o # RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \ # RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=48 -# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb +# RUN: yaml2obj --docnum=1 -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb # RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o # RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \ # RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=48 @@ -147,4 +147,52 @@ Sections: - Name: LINUX Type: 0x01 Desc: 0102 -... + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=TEST2 +# TEST2: warning: note segments are not supported +# TEST2-NOT: note segments are not supported + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_CORE + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_NOTE + FirstSec: .data0 + LastSec: .data0 + - Type: PT_NOTE + FirstSec: .data1 + LastSec: .data1 +Sections: + - Name: .data0 + Type: Fill + Size: 8 + - Name: .data1 + Type: Fill + Size: 8 + +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-objcopy --remove-note=1 %t3 %t3o 2>&1 | FileCheck %s --check-prefix=TEST3 +# TEST3: warning: cannot remove note(s) from .note: sections in segments are not supported + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_LOAD + FirstSec: .note + LastSec: .note +Sections: + - Name: .note + Type: SHT_NOTE + AddressAlign: 4 + Notes: + - Name: ABC + Type: 1 + Desc: 0102