Skip to content

Commit b28412d

Browse files
committed
[llvm-objcopy][ELF] Add --set-section-type
The request is mentioned on D129053. I feel that having this functionality is mildly useful (not strong). * Rename .ctors to .init_array and change sh_type to SHT_INIT_ARRAY (GNU objcopy detects the special name but we don't). * Craft tests for a new SHT_LLVM_* extension Reviewed By: jhenderson Differential Revision: https://reviews.llvm.org/D129337
1 parent 31ccceb commit b28412d

File tree

11 files changed

+151
-60
lines changed

11 files changed

+151
-60
lines changed

llvm/docs/CommandGuide/llvm-objcopy.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,11 @@ them.
428428
specified ``<flag>`` values. See :option:`--set-section-flags` for a list of
429429
supported flags. Can be specified multiple times to rename multiple sections.
430430

431+
.. option:: --set-section-type <section>=<type>
432+
433+
Set the type of section ``<section>`` to the integer ``<type>``. Can be
434+
specified multiple times to update multiple sections.
435+
431436
.. option:: --set-start-addr <addr>
432437

433438
Set the start address of the output to ``<addr>``. Overrides any previously

llvm/include/llvm/ObjCopy/CommonConfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ struct CommonConfig {
241241
StringMap<SectionRename> SectionsToRename;
242242
StringMap<uint64_t> SetSectionAlignment;
243243
StringMap<SectionFlagsUpdate> SetSectionFlags;
244+
StringMap<uint64_t> SetSectionType;
244245
StringMap<StringRef> SymbolsToRename;
245246

246247
// Symbol info specified by --add-symbol option.

llvm/lib/ObjCopy/ConfigManager.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {
2020
!Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() ||
2121
!Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
2222
!Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
23-
Common.ExtractDWO || Common.PreserveDates || Common.StripDWO ||
24-
Common.StripNonAlloc || Common.StripSections || Common.Weaken ||
25-
Common.DecompressDebugSections ||
23+
!Common.SetSectionType.empty() || Common.ExtractDWO ||
24+
Common.PreserveDates || Common.StripDWO || Common.StripNonAlloc ||
25+
Common.StripSections || Common.Weaken || Common.DecompressDebugSections ||
2626
Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty())
2727
return createStringError(llvm::errc::invalid_argument,
2828
"option is not supported for COFF");
@@ -38,9 +38,10 @@ Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
3838
!Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() ||
3939
!Common.UnneededSymbolsToRemove.empty() ||
4040
!Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() ||
41-
Common.ExtractDWO || Common.PreserveDates || Common.StripAllGNU ||
42-
Common.StripDWO || Common.StripNonAlloc || Common.StripSections ||
43-
Common.Weaken || Common.DecompressDebugSections || Common.StripUnneeded ||
41+
!Common.SetSectionType.empty() || Common.ExtractDWO ||
42+
Common.PreserveDates || Common.StripAllGNU || Common.StripDWO ||
43+
Common.StripNonAlloc || Common.StripSections || Common.Weaken ||
44+
Common.DecompressDebugSections || Common.StripUnneeded ||
4445
Common.DiscardMode == DiscardType::Locals || !Common.SymbolsToAdd.empty())
4546
return createStringError(llvm::errc::invalid_argument,
4647
"option is not supported for MachO");
@@ -58,7 +59,8 @@ Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
5859
!Common.UnneededSymbolsToRemove.empty() ||
5960
!Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
6061
!Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
61-
!Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty())
62+
!Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() ||
63+
!Common.SymbolsToRename.empty())
6264
return createStringError(llvm::errc::invalid_argument,
6365
"only flags for section dumping, removal, and "
6466
"addition are supported");
@@ -79,12 +81,12 @@ Expected<const XCOFFConfig &> ConfigManager::getXCOFFConfig() const {
7981
!Common.UnneededSymbolsToRemove.empty() ||
8082
!Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
8183
!Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
82-
!Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty() ||
83-
Common.ExtractDWO || Common.ExtractMainPartition ||
84-
Common.OnlyKeepDebug || Common.PreserveDates || Common.StripAllGNU ||
85-
Common.StripDWO || Common.StripDebug || Common.StripNonAlloc ||
86-
Common.StripSections || Common.Weaken || Common.StripUnneeded ||
87-
Common.DecompressDebugSections) {
84+
!Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() ||
85+
!Common.SymbolsToRename.empty() || Common.ExtractDWO ||
86+
Common.ExtractMainPartition || Common.OnlyKeepDebug ||
87+
Common.PreserveDates || Common.StripAllGNU || Common.StripDWO ||
88+
Common.StripDebug || Common.StripNonAlloc || Common.StripSections ||
89+
Common.Weaken || Common.StripUnneeded || Common.DecompressDebugSections) {
8890
return createStringError(
8991
llvm::errc::invalid_argument,
9092
"no flags are supported yet, only basic copying is allowed");

llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,14 +675,17 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
675675
for (const NewSymbolInfo &SI : Config.SymbolsToAdd)
676676
addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility);
677677

678-
// --set-section-flags works with sections added by --add-section.
679-
if (!Config.SetSectionFlags.empty()) {
678+
// --set-section-{flags,type} work with sections added by --add-section.
679+
if (!Config.SetSectionFlags.empty() || !Config.SetSectionType.empty()) {
680680
for (auto &Sec : Obj.sections()) {
681681
const auto Iter = Config.SetSectionFlags.find(Sec.Name);
682682
if (Iter != Config.SetSectionFlags.end()) {
683683
const SectionFlagsUpdate &SFU = Iter->second;
684684
setSectionFlagsAndType(Sec, SFU.NewFlags);
685685
}
686+
auto It2 = Config.SetSectionType.find(Sec.Name);
687+
if (It2 != Config.SetSectionType.end())
688+
Sec.Type = It2->second;
686689
}
687690
}
688691

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## Check --set-section-flags/--set-section-types work with sections added by --add-section.
2+
3+
# RUN: yaml2obj %s -o %t
4+
# RUN: llvm-objcopy --add-section=foo=/dev/null --set-section-flags=foo=alloc,exclude %t %t.1
5+
# RUN: llvm-readobj -S %t.1 | FileCheck %s
6+
7+
# CHECK: Name: foo
8+
# CHECK-NEXT: Type: SHT_PROGBITS
9+
# CHECK-NEXT: Flags [
10+
# CHECK-NEXT: SHF_ALLOC
11+
# CHECK-NEXT: SHF_EXCLUDE
12+
# CHECK-NEXT: SHF_WRITE
13+
# CHECK-NEXT: ]
14+
15+
# RUN: llvm-objcopy --add-section=foo=/dev/null --set-section-type=foo=7 %t %t.2
16+
# RUN: llvm-readobj -S %t.2 | FileCheck %s --check-prefix=CHECK2
17+
18+
# CHECK2: Name: foo
19+
# CHECK2-NEXT: Type: SHT_NOTE (0x7)
20+
# CHECK2-NEXT: Flags [
21+
# CHECK2-NEXT: ]
22+
23+
--- !ELF
24+
FileHeader:
25+
Class: ELFCLASS64
26+
Data: ELFDATA2LSB
27+
Type: ET_EXEC
28+
Machine: EM_X86_64

llvm/test/tools/llvm-objcopy/ELF/add-section-and-set-flags.test

Lines changed: 0 additions & 20 deletions
This file was deleted.

llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
# RUN: not llvm-objcopy --set-section-alignment=.foo=bar %t /dev/null 2>&1 | \
4545
# RUN: FileCheck --check-prefix=INVALID-ALIGN %s
46-
# INVALID-ALIGN: error: invalid alignment for --set-section-alignment: 'bar'
46+
# INVALID-ALIGN: error: invalid value for --set-section-alignment: 'bar'
4747

4848
!ELF
4949
FileHeader:

llvm/test/tools/llvm-objcopy/ELF/set-section-attr-and-rename.test

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# RUN: yaml2obj %s -o %t
22

3-
# RUN: llvm-objcopy --rename-section=.foo=.bar --set-section-alignment=.foo=16 --set-section-flags=.foo=alloc %t %t.1
3+
# RUN: llvm-objcopy --rename-section=.foo=.bar --set-section-alignment=.foo=16 --set-section-flags=.foo=alloc --set-section-type=.foo=5 %t %t.1
44
# RUN: llvm-readobj -S %t.1 | FileCheck %s
55

66
# CHECK: Name: .bar
7-
# CHECK-NEXT: Type: SHT_PROGBITS
7+
# CHECK-NEXT: Type: SHT_HASH (0x5)
88
# CHECK-NEXT: Flags [
99
# CHECK-NEXT: SHF_ALLOC
1010
# CHECK-NEXT: SHF_WRITE
@@ -13,7 +13,12 @@
1313
# CHECK-SAME: {{^}} 16
1414

1515
# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.bar=alloc %t %t.2 2>&1 | \
16-
# RUN: FileCheck %s --check-prefix=SET-BAR
16+
# RUN: FileCheck %s --check-prefix=SET-BAR1
17+
# SET-BAR1: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar
18+
19+
# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-type=.bar=1 %t %t.2 2>&1 | \
20+
# RUN: FileCheck %s --check-prefix=SET-BAR2
21+
# SET-BAR2: --set-section-type=.bar conflicts with --rename-section=.foo=.bar
1722

1823
!ELF
1924
FileHeader:
@@ -25,5 +30,3 @@ Sections:
2530
- Name: .foo
2631
Type: SHT_PROGBITS
2732
Flags: [ SHF_ALLOC ]
28-
29-
# SET-BAR: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# RUN: yaml2obj %s -o %t
2+
3+
# RUN: llvm-objcopy --set-section-type=.foo=14 --set-section-type .bar=0xf %t %t.1
4+
# RUN: llvm-readobj --sections %t.1 | FileCheck %s
5+
6+
# RUN: llvm-objcopy --set-section-type=.foo=13 --set-section-type=.foo=14 --set-section-type .bar=0xf %t %t.1
7+
# RUN: llvm-readobj --sections %t.1 | FileCheck %s
8+
9+
# CHECK: Name: .foo
10+
# CHECK-NEXT: Type: SHT_INIT_ARRAY (0xE)
11+
# CHECK-NEXT: Flags [
12+
# CHECK-NEXT: SHF_ALLOC
13+
# CHECK-NEXT: ]
14+
15+
# CHECK: Name: .bar
16+
# CHECK-NEXT: Type: SHT_FINI_ARRAY (0xF)
17+
# CHECK-NEXT: Flags [
18+
# CHECK-NEXT: ]
19+
20+
## --set-section-flags does not specify "readonly", so the output gets SHF_WRITE.
21+
## "contents" changes SHT_NOBITS to SHT_PROGBITS, but this is overridden by --set-section-type.
22+
## sh_type is a uint32_t. There is no diagnostic for an overflow value.
23+
# RUN: llvm-objcopy --set-section-flags=.foo=alloc,contents --set-section-type=.foo=0x10000000a %t %t.2 2>&1 | count 0
24+
# RUN: llvm-readobj --sections %t.2 | FileCheck %s --check-prefix=CHECK2
25+
26+
# CHECK2: Name: .foo
27+
# CHECK2-NEXT: Type: SHT_SHLIB
28+
# CHECK2-NEXT: Flags [
29+
# CHECK2-NEXT: SHF_ALLOC
30+
# CHECK2-NEXT: SHF_WRITE
31+
# CHECK2-NEXT: ]
32+
33+
# RUN: not llvm-objcopy --set-section-type=.foo %t /dev/null 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
34+
# BAD-FORMAT: bad format for --set-section-type: missing '='
35+
36+
# RUN: not llvm-objcopy --set-section-type==4 %t /dev/null 2>&1 | FileCheck %s --check-prefix=MISSING-SECTION
37+
# MISSING-SECTION: error: bad format for --set-section-type: missing section name
38+
39+
# RUN: not llvm-objcopy --set-section-type=.foo=aaa %t /dev/null 2>&1 | FileCheck %s --check-prefix=INVALID-TYPE
40+
# INVALID-TYPE: error: invalid value for --set-section-type: 'aaa'
41+
42+
!ELF
43+
FileHeader:
44+
Class: ELFCLASS64
45+
Data: ELFDATA2LSB
46+
Type: ET_REL
47+
Machine: EM_X86_64
48+
Sections:
49+
- Name: .foo
50+
Type: SHT_NOBITS
51+
Flags: [ SHF_ALLOC ]
52+
- Name: .bar
53+
Type: SHT_PROGBITS
54+
Flags: [ ]

llvm/tools/llvm-objcopy/ObjcopyOptions.cpp

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -236,23 +236,21 @@ static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {
236236
}
237237

238238
static Expected<std::pair<StringRef, uint64_t>>
239-
parseSetSectionAlignment(StringRef FlagValue) {
239+
parseSetSectionAttribute(StringRef Option, StringRef FlagValue) {
240240
if (!FlagValue.contains('='))
241-
return createStringError(
242-
errc::invalid_argument,
243-
"bad format for --set-section-alignment: missing '='");
241+
return make_error<StringError>("bad format for " + Option + ": missing '='",
242+
errc::invalid_argument);
244243
auto Split = StringRef(FlagValue).split('=');
245244
if (Split.first.empty())
246-
return createStringError(
247-
errc::invalid_argument,
248-
"bad format for --set-section-alignment: missing section name");
249-
uint64_t NewAlign;
250-
if (Split.second.getAsInteger(0, NewAlign))
251-
return createStringError(
252-
errc::invalid_argument,
253-
"invalid alignment for --set-section-alignment: '%s'",
254-
Split.second.str().c_str());
255-
return std::make_pair(Split.first, NewAlign);
245+
return make_error<StringError>("bad format for " + Option +
246+
": missing section name",
247+
errc::invalid_argument);
248+
uint64_t Value;
249+
if (Split.second.getAsInteger(0, Value))
250+
return make_error<StringError>("invalid value for " + Option + ": '" +
251+
Split.second + "'",
252+
errc::invalid_argument);
253+
return std::make_pair(Split.first, Value);
256254
}
257255

258256
static Expected<SectionFlagsUpdate>
@@ -793,7 +791,7 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
793791
}
794792
for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
795793
Expected<std::pair<StringRef, uint64_t>> NameAndAlign =
796-
parseSetSectionAlignment(Arg->getValue());
794+
parseSetSectionAttribute("--set-section-alignment", Arg->getValue());
797795
if (!NameAndAlign)
798796
return NameAndAlign.takeError();
799797
Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;
@@ -809,16 +807,28 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
809807
"--set-section-flags set multiple times for section '%s'",
810808
SFU->Name.str().c_str());
811809
}
812-
// Prohibit combinations of --set-section-flags when the section name is used
813-
// as the destination of a --rename-section.
810+
for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_type)) {
811+
Expected<std::pair<StringRef, uint64_t>> NameAndType =
812+
parseSetSectionAttribute("--set-section-type", Arg->getValue());
813+
if (!NameAndType)
814+
return NameAndType.takeError();
815+
Config.SetSectionType[NameAndType->first] = NameAndType->second;
816+
}
817+
// Prohibit combinations of --set-section-{flags,type} when the section name
818+
// is used as the destination of a --rename-section.
814819
for (const auto &E : Config.SectionsToRename) {
815820
const SectionRename &SR = E.second;
816-
if (Config.SetSectionFlags.count(SR.NewName))
821+
auto Err = [&](const char *Option) {
817822
return createStringError(
818823
errc::invalid_argument,
819-
"--set-section-flags=%s conflicts with --rename-section=%s=%s",
824+
"--set-section-%s=%s conflicts with --rename-section=%s=%s", Option,
820825
SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
821826
SR.NewName.str().c_str());
827+
};
828+
if (Config.SetSectionFlags.count(SR.NewName))
829+
return Err("flags");
830+
if (Config.SetSectionType.count(SR.NewName))
831+
return Err("type");
822832
}
823833

824834
for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))

llvm/tools/llvm-objcopy/ObjcopyOpts.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ defm set_section_flags
8787
"data, rom, share, contents, merge, strings.">,
8888
MetaVarName<"section=flag1[,flag2,...]">;
8989

90+
defm set_section_type
91+
: Eq<"set-section-type",
92+
"Set the type of section <section> to the integer <type>">,
93+
MetaVarName<"section=type">;
94+
9095
def S : Flag<["-"], "S">,
9196
Alias<strip_all>,
9297
HelpText<"Alias for --strip-all">;

0 commit comments

Comments
 (0)