From 7c03b7d668dcc0c6937d41e131fa0a07b62f907b Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 11 Jul 2022 09:04:45 -0700 Subject: [PATCH] [llvm-objcopy][ELF] Allow --set-section-flags src=... and --rename-section src=tst * GNU objcopy supports --set-section-flags src=... --rename-section src=tst and --set-section-flags runs first. * GNU objcopy processes --update-section before --rename-section. To match the two behaviors, postpone --rename-section and allow its use together with --set-section-flags. As a side effect, --rename-section=.foo1=.foo2 --add-section=.foo1=/dev/null leads to .foo2 while GNU objcopy surprisingly produces .foo1 (so --set-section-flags --add-section --rename-section do not form a total order). I think the deviation is fine as a total order makes more sense. Rename set-section-flags-and-rename.test to set-section-attr-and-rename.test and additionally test --set-section-alignment Reviewed By: jhenderson Differential Revision: https://reviews.llvm.org/D129336 --- llvm/docs/ReleaseNotes.rst | 2 + llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 114 ++++++++++----------- .../ELF/rename-section-and-update.test | 29 ++++++ .../ELF/set-section-attr-and-rename.test | 29 ++++++ .../ELF/set-section-flags-and-rename.test | 14 --- llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 8 +- 6 files changed, 118 insertions(+), 78 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/ELF/rename-section-and-update.test create mode 100644 llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test delete mode 100644 llvm/test/tools/llvm-objcopy/ELF/set-section-flags-and-rename.test diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index 9b0eb6f..1268cc7 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -233,6 +233,8 @@ Changes to the LLVM tools filter :doc:`Symbolizer Markup ` into human-readable form. * :doc:`llvm-objcopy ` has removed support for the legacy ``zlib-gnu`` format. +* :doc:`llvm-objcopy ` now allows ``--set-section-flags src=... --rename-section src=tst``. + ``--add-section=.foo1=... --rename-section=.foo1=.foo2`` now adds ``.foo1`` instead of ``.foo2``. Changes to LLDB --------------------------------- diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 2d388f8..ee592bb 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -629,6 +629,63 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, if (Error E = updateAndRemoveSymbols(Config, ELFConfig, Obj)) return E; + if (!Config.SetSectionAlignment.empty()) { + for (SectionBase &Sec : Obj.sections()) { + auto I = Config.SetSectionAlignment.find(Sec.Name); + if (I != Config.SetSectionAlignment.end()) + Sec.Align = I->second; + } + } + + if (Config.OnlyKeepDebug) + for (auto &Sec : Obj.sections()) + if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) + Sec.Type = SHT_NOBITS; + + for (const NewSectionInfo &AddedSection : Config.AddSection) { + auto AddSection = [&](StringRef Name, ArrayRef Data) { + OwnedDataSection &NewSection = + Obj.addSection(Name, Data); + if (Name.startswith(".note") && Name != ".note.GNU-stack") + NewSection.Type = SHT_NOTE; + return Error::success(); + }; + if (Error E = handleUserSection(AddedSection, AddSection)) + return E; + } + + for (const NewSectionInfo &NewSection : Config.UpdateSection) { + auto UpdateSection = [&](StringRef Name, ArrayRef Data) { + return Obj.updateSection(Name, Data); + }; + if (Error E = handleUserSection(NewSection, UpdateSection)) + return E; + } + + if (!Config.AddGnuDebugLink.empty()) + Obj.addSection(Config.AddGnuDebugLink, + Config.GnuDebugLinkCRC32); + + // If the symbol table was previously removed, we need to create a new one + // before adding new symbols. + if (!Obj.SymbolTable && !Config.SymbolsToAdd.empty()) + if (Error E = Obj.addNewSymbolTable()) + return E; + + for (const NewSymbolInfo &SI : Config.SymbolsToAdd) + addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility); + + // --set-section-flags works with sections added by --add-section. + if (!Config.SetSectionFlags.empty()) { + for (auto &Sec : Obj.sections()) { + const auto Iter = Config.SetSectionFlags.find(Sec.Name); + if (Iter != Config.SetSectionFlags.end()) { + const SectionFlagsUpdate &SFU = Iter->second; + setSectionFlagsAndType(Sec, SFU.NewFlags); + } + } + } + if (!Config.SectionsToRename.empty()) { std::vector RelocSections; DenseSet RenamedSections; @@ -693,63 +750,6 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, } } - if (!Config.SetSectionAlignment.empty()) { - for (SectionBase &Sec : Obj.sections()) { - auto I = Config.SetSectionAlignment.find(Sec.Name); - if (I != Config.SetSectionAlignment.end()) - Sec.Align = I->second; - } - } - - if (Config.OnlyKeepDebug) - for (auto &Sec : Obj.sections()) - if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) - Sec.Type = SHT_NOBITS; - - for (const NewSectionInfo &AddedSection : Config.AddSection) { - auto AddSection = [&](StringRef Name, ArrayRef Data) { - OwnedDataSection &NewSection = - Obj.addSection(Name, Data); - if (Name.startswith(".note") && Name != ".note.GNU-stack") - NewSection.Type = SHT_NOTE; - return Error::success(); - }; - if (Error E = handleUserSection(AddedSection, AddSection)) - return E; - } - - for (const NewSectionInfo &NewSection : Config.UpdateSection) { - auto UpdateSection = [&](StringRef Name, ArrayRef Data) { - return Obj.updateSection(Name, Data); - }; - if (Error E = handleUserSection(NewSection, UpdateSection)) - return E; - } - - if (!Config.AddGnuDebugLink.empty()) - Obj.addSection(Config.AddGnuDebugLink, - Config.GnuDebugLinkCRC32); - - // If the symbol table was previously removed, we need to create a new one - // before adding new symbols. - if (!Obj.SymbolTable && !Config.SymbolsToAdd.empty()) - if (Error E = Obj.addNewSymbolTable()) - return E; - - for (const NewSymbolInfo &SI : Config.SymbolsToAdd) - addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility); - - // --set-section-flags works with sections added by --add-section. - if (!Config.SetSectionFlags.empty()) { - for (auto &Sec : Obj.sections()) { - const auto Iter = Config.SetSectionFlags.find(Sec.Name); - if (Iter != Config.SetSectionFlags.end()) { - const SectionFlagsUpdate &SFU = Iter->second; - setSectionFlagsAndType(Sec, SFU.NewFlags); - } - } - } - if (ELFConfig.EntryExpr) Obj.Entry = ELFConfig.EntryExpr(Obj.Entry); return Error::success(); diff --git a/llvm/test/tools/llvm-objcopy/ELF/rename-section-and-update.test b/llvm/test/tools/llvm-objcopy/ELF/rename-section-and-update.test new file mode 100644 index 0000000..a684e7a --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/rename-section-and-update.test @@ -0,0 +1,29 @@ +## --add-section is handled before --rename-section. Note: GNU objcopy produces .foo2. +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --rename-section=.foo1=.foo2 --add-section=.foo1=/dev/null %t %t.1 +# RUN: llvm-readobj -S %t.1 | FileCheck %s + +# CHECK: Name: .foo2 +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] + +## --update-section is handled before --rename-section. +# RUN: echo 00 > %t.nop +# RUN: llvm-objcopy --rename-section=.text=.text2 --update-section=.text=%t.nop %t %t.2 +# RUN: llvm-readelf -x .text2 %t.2 | FileCheck %s --check-prefix=CHECK2 + +# CHECK2: Hex dump of section '.text2': +# CHECK2-NEXT: 0x00000000 30300a + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Content: "c3c3c3" diff --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test new file mode 100644 index 0000000..ba6f521 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test @@ -0,0 +1,29 @@ +# RUN: yaml2obj %s -o %t + +# RUN: llvm-objcopy --rename-section=.foo=.bar --set-section-alignment=.foo=16 --set-section-flags=.foo=alloc %t %t.1 +# RUN: llvm-readobj -S %t.1 | FileCheck %s + +# CHECK: Name: .bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK: AddressAlignment: +# CHECK-SAME: {{^}} 16 + +# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.bar=alloc %t %t.2 2>&1 | \ +# RUN: FileCheck %s --check-prefix=SET-BAR + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + +# SET-BAR: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar diff --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-and-rename.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-and-rename.test deleted file mode 100644 index 4b553b3..0000000 --- a/llvm/test/tools/llvm-objcopy/ELF/set-section-flags-and-rename.test +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: yaml2obj %s -o %t - -# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.foo=alloc %t %t.2 2>&1 | FileCheck %s --check-prefix=SET-FOO -# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.bar=alloc %t %t.2 2>&1 | FileCheck %s --check-prefix=SET-BAR - -!ELF -FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_REL - Machine: EM_X86_64 - -# SET-FOO: --set-section-flags=.foo conflicts with --rename-section=.foo=.bar -# SET-BAR: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp index 94841ef..30ca506 100644 --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -810,15 +810,9 @@ objcopy::parseObjcopyOptions(ArrayRef RawArgsArr, SFU->Name.str().c_str()); } // Prohibit combinations of --set-section-flags when the section name is used - // by --rename-section, either as a source or a destination. + // as the destination of a --rename-section. for (const auto &E : Config.SectionsToRename) { const SectionRename &SR = E.second; - if (Config.SetSectionFlags.count(SR.OriginalName)) - return createStringError( - errc::invalid_argument, - "--set-section-flags=%s conflicts with --rename-section=%s=%s", - SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(), - SR.NewName.str().c_str()); if (Config.SetSectionFlags.count(SR.NewName)) return createStringError( errc::invalid_argument, -- 2.7.4