[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
This commit is contained in:
Fangrui Song 2022-07-11 09:04:45 -07:00
parent 0af2680596
commit 7c03b7d668
6 changed files with 118 additions and 78 deletions

View File

@ -233,6 +233,8 @@ Changes to the LLVM tools
filter :doc:`Symbolizer Markup </SymbolizerMarkupFormat>` into human-readable
form.
* :doc:`llvm-objcopy <CommandGuide/llvm-objcopy>` has removed support for the legacy ``zlib-gnu`` format.
* :doc:`llvm-objcopy <CommandGuide/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
---------------------------------

View File

@ -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<uint8_t> Data) {
OwnedDataSection &NewSection =
Obj.addSection<OwnedDataSection>(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<uint8_t> Data) {
return Obj.updateSection(Name, Data);
};
if (Error E = handleUserSection(NewSection, UpdateSection))
return E;
}
if (!Config.AddGnuDebugLink.empty())
Obj.addSection<GnuDebugLinkSection>(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<RelocationSectionBase *> RelocSections;
DenseSet<SectionBase *> 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<uint8_t> Data) {
OwnedDataSection &NewSection =
Obj.addSection<OwnedDataSection>(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<uint8_t> Data) {
return Obj.updateSection(Name, Data);
};
if (Error E = handleUserSection(NewSection, UpdateSection))
return E;
}
if (!Config.AddGnuDebugLink.empty())
Obj.addSection<GnuDebugLinkSection>(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();

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -810,15 +810,9 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> 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,