Skip to content

Commit c892741

Browse files
committed
[llvm-objcopy] Implement --set-section-flags.
Summary: --set-section-flags is used to change the section flags (e.g. SHF_ALLOC) for given sections. The flags allowed are the same from the existing --rename-section=.old=.new[,flags] feature. Additionally, make sure that --set-section-flag cannot be used with --rename-section (either the source or destination), since --rename-section accepts flags. This avoids ambiguity for something like "--rename-section=.foo=.bar,alloc --set-section-flag=.bar,code". Reviewers: jhenderson, jakehehrlich, alexshap, espindola Reviewed By: jhenderson, jakehehrlich Subscribers: llvm-commits, emaste, arichardson Differential Revision: https://reviews.llvm.org/D57198 llvm-svn: 352505
1 parent a1f6973 commit c892741

File tree

8 files changed

+218
-38
lines changed

8 files changed

+218
-38
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# RUN: yaml2obj %s > %t
2+
3+
# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.foo=alloc %t %t.2 2>&1 | FileCheck %s --check-prefix=SET-FOO
4+
# RUN: not llvm-objcopy --rename-section=.foo=.bar --set-section-flags=.bar=alloc %t %t.2 2>&1 | FileCheck %s --check-prefix=SET-BAR
5+
6+
!ELF
7+
FileHeader:
8+
Class: ELFCLASS64
9+
Data: ELFDATA2LSB
10+
Type: ET_REL
11+
Machine: EM_X86_64
12+
13+
# SET-FOO: --set-section-flags=.foo conflicts with --rename-section=.foo=.bar.
14+
# SET-BAR: --set-section-flags=.bar conflicts with --rename-section=.foo=.bar.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# RUN: yaml2obj %s > %t
2+
3+
# RUN: llvm-objcopy --set-section-flags=.foo=alloc --set-section-flags=.bar=code %t %t.2
4+
# RUN: llvm-readobj --sections %t.2 | FileCheck %s --check-prefixes=CHECK,ALLOC,WRITE
5+
6+
!ELF
7+
FileHeader:
8+
Class: ELFCLASS64
9+
Data: ELFDATA2LSB
10+
Type: ET_REL
11+
Machine: EM_X86_64
12+
Sections:
13+
- Name: .foo
14+
Type: SHT_PROGBITS
15+
Flags: [ ]
16+
- Name: .bar
17+
Type: SHT_PROGBITS
18+
Flags: [ ]
19+
20+
# CHECK: Name: .foo
21+
# CHECK-NEXT: Type: SHT_PROGBITS
22+
# CHECK-NEXT: Flags [
23+
# CHECK-NEXT: SHF_ALLOC (0x2)
24+
# CHECK-NEXT: SHF_WRITE (0x1)
25+
# CHECK-NEXT: ]
26+
27+
# CHECK: Name: .bar
28+
# CHECK-NEXT: Type: SHT_PROGBITS
29+
# CHECK-NEXT: Flags [
30+
# CHECK-NEXT: SHF_EXECINSTR (0x4)
31+
# CHECK-NEXT: SHF_WRITE (0x1)
32+
# CHECK-NEXT: ]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# RUN: yaml2obj %s > %t
2+
3+
# Single flags on a section with no flags:
4+
# RUN: llvm-objcopy --set-section-flags=.foo=alloc %t %t.alloc
5+
# RUN: llvm-readobj --sections %t.alloc | FileCheck %s --check-prefixes=CHECK,ALLOC,WRITE
6+
# RUN: llvm-objcopy --set-section-flags=.foo=load %t %t.load
7+
# RUN: llvm-readobj --sections %t.load | FileCheck %s --check-prefixes=CHECK,WRITE
8+
# RUN: llvm-objcopy --set-section-flags=.foo=noload %t %t.noload
9+
# RUN: llvm-readobj --sections %t.noload | FileCheck %s --check-prefixes=CHECK,WRITE
10+
# RUN: llvm-objcopy --set-section-flags=.foo=readonly %t %t.readonly
11+
# RUN: llvm-readobj --sections %t.readonly | FileCheck %s --check-prefixes=CHECK
12+
# RUN: llvm-objcopy --set-section-flags=.foo=debug %t %t.debug
13+
# RUN: llvm-readobj --sections %t.debug | FileCheck %s --check-prefixes=CHECK,WRITE
14+
# RUN: llvm-objcopy --set-section-flags=.foo=code %t %t.code
15+
# RUN: llvm-readobj --sections %t.code | FileCheck %s --check-prefixes=CHECK,EXEC,WRITE
16+
# RUN: llvm-objcopy --set-section-flags=.foo=data %t %t.data
17+
# RUN: llvm-readobj --sections %t.data | FileCheck %s --check-prefixes=CHECK,WRITE
18+
# RUN: llvm-objcopy --set-section-flags=.foo=rom %t %t.rom
19+
# RUN: llvm-readobj --sections %t.rom | FileCheck %s --check-prefixes=CHECK,WRITE
20+
# RUN: llvm-objcopy --set-section-flags=.foo=contents %t %t.contents
21+
# RUN: llvm-readobj --sections %t.contents | FileCheck %s --check-prefixes=CHECK,WRITE
22+
# RUN: llvm-objcopy --set-section-flags=.foo=merge %t %t.merge
23+
# RUN: llvm-readobj --sections %t.merge | FileCheck %s --check-prefixes=CHECK,MERGE,WRITE
24+
# RUN: llvm-objcopy --set-section-flags=.foo=strings %t %t.strings
25+
# RUN: llvm-readobj --sections %t.strings | FileCheck %s --check-prefixes=CHECK,STRINGS,WRITE
26+
# RUN: llvm-objcopy --set-section-flags=.foo=share %t %t.share
27+
# RUN: llvm-readobj --sections %t.share | FileCheck %s --check-prefixes=CHECK,WRITE
28+
29+
# Multiple flags:
30+
# RUN: llvm-objcopy --set-section-flags=.foo=alloc,readonly,strings %t %t.alloc_ro_strings
31+
# RUN: llvm-readobj --sections %t.alloc_ro_strings | FileCheck %s --check-prefixes=CHECK,ALLOC,STRINGS
32+
# RUN: llvm-objcopy --set-section-flags=.foo=alloc,code %t %t.alloc_code
33+
# RUN: llvm-readobj --sections %t.alloc_code | FileCheck %s --check-prefixes=CHECK,ALLOC,EXEC,WRITE
34+
35+
# Invalid flags:
36+
# RUN: not llvm-objcopy --set-section-flags=.foo=xyzzy %t %t.xyzzy 2>&1 | FileCheck %s --check-prefix=BAD-FLAG
37+
38+
# Bad flag format:
39+
# RUN: not llvm-objcopy --set-section-flags=.foo %t %t2 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
40+
41+
# Setting flags for the same section multiple times:
42+
# RUN: not llvm-objcopy --set-section-flags=.foo=alloc --set-section-flags=.foo=load %t %t2 2>&1 | FileCheck %s --check-prefix=MULTIPLE-SETS
43+
44+
!ELF
45+
FileHeader:
46+
Class: ELFCLASS64
47+
Data: ELFDATA2LSB
48+
Type: ET_REL
49+
Machine: EM_X86_64
50+
Sections:
51+
- Name: .foo
52+
Type: SHT_PROGBITS
53+
Flags: [ ]
54+
55+
# CHECK: Name: .foo
56+
# CHECK-NEXT: Type: SHT_PROGBITS
57+
# CHECK-NEXT: Flags [
58+
# ALLOC-NEXT: SHF_ALLOC (0x2)
59+
# EXEC-NEXT: SHF_EXECINSTR (0x4)
60+
# MERGE-NEXT: SHF_MERGE (0x10)
61+
# STRINGS-NEXT: SHF_STRINGS (0x20)
62+
# WRITE-NEXT: SHF_WRITE (0x1)
63+
# CHECK-NEXT: ]
64+
65+
# BAD-FORMAT: Bad format for --set-section-flags: missing '='
66+
# MULTIPLE-SETS: --set-section-flags set multiple times for section .foo
67+
68+
# BAD-FLAG: Unrecognized section flag 'xyzzy'. Flags supported for GNU compatibility: alloc, load, noload, readonly, debug, code, data, rom, share, contents, merge, strings.

llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
177177
!Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
178178
!Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
179179
!Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
180-
!Config.SymbolsToRename.empty() || Config.ExtractDWO ||
181-
Config.KeepFileSymbols || Config.LocalizeHidden || Config.PreserveDates ||
182-
Config.StripDWO || Config.StripNonAlloc || Config.StripSections ||
183-
Config.Weaken || Config.DecompressDebugSections) {
180+
!Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty() ||
181+
Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden ||
182+
Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc ||
183+
Config.StripSections || Config.Weaken || Config.DecompressDebugSections) {
184184
return createStringError(llvm::errc::invalid_argument,
185185
"Option not supported by llvm-objcopy for COFF");
186186
}

llvm/tools/llvm-objcopy/CopyConfig.cpp

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,32 @@ static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
128128
.Default(SectionFlag::SecNone);
129129
}
130130

131+
static uint64_t parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
132+
SectionFlag ParsedFlags = SectionFlag::SecNone;
133+
for (StringRef Flag : SectionFlags) {
134+
SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
135+
if (ParsedFlag == SectionFlag::SecNone)
136+
error("Unrecognized section flag '" + Flag +
137+
"'. Flags supported for GNU compatibility: alloc, load, noload, "
138+
"readonly, debug, code, data, rom, share, contents, merge, "
139+
"strings.");
140+
ParsedFlags |= ParsedFlag;
141+
}
142+
143+
uint64_t NewFlags = 0;
144+
if (ParsedFlags & SectionFlag::SecAlloc)
145+
NewFlags |= ELF::SHF_ALLOC;
146+
if (!(ParsedFlags & SectionFlag::SecReadonly))
147+
NewFlags |= ELF::SHF_WRITE;
148+
if (ParsedFlags & SectionFlag::SecCode)
149+
NewFlags |= ELF::SHF_EXECINSTR;
150+
if (ParsedFlags & SectionFlag::SecMerge)
151+
NewFlags |= ELF::SHF_MERGE;
152+
if (ParsedFlags & SectionFlag::SecStrings)
153+
NewFlags |= ELF::SHF_STRINGS;
154+
return NewFlags;
155+
}
156+
131157
static SectionRename parseRenameSectionValue(StringRef FlagValue) {
132158
if (!FlagValue.contains('='))
133159
error("Bad format for --rename-section: missing '='");
@@ -142,34 +168,29 @@ static SectionRename parseRenameSectionValue(StringRef FlagValue) {
142168
Old2New.second.split(NameAndFlags, ',');
143169
SR.NewName = NameAndFlags[0];
144170

145-
if (NameAndFlags.size() > 1) {
146-
SectionFlag Flags = SectionFlag::SecNone;
147-
for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
148-
SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]);
149-
if (Flag == SectionFlag::SecNone)
150-
error("Unrecognized section flag '" + NameAndFlags[I] +
151-
"'. Flags supported for GNU compatibility: alloc, load, noload, "
152-
"readonly, debug, code, data, rom, share, contents, merge, "
153-
"strings.");
154-
Flags |= Flag;
155-
}
156-
157-
SR.NewFlags = 0;
158-
if (Flags & SectionFlag::SecAlloc)
159-
*SR.NewFlags |= ELF::SHF_ALLOC;
160-
if (!(Flags & SectionFlag::SecReadonly))
161-
*SR.NewFlags |= ELF::SHF_WRITE;
162-
if (Flags & SectionFlag::SecCode)
163-
*SR.NewFlags |= ELF::SHF_EXECINSTR;
164-
if (Flags & SectionFlag::SecMerge)
165-
*SR.NewFlags |= ELF::SHF_MERGE;
166-
if (Flags & SectionFlag::SecStrings)
167-
*SR.NewFlags |= ELF::SHF_STRINGS;
168-
}
171+
if (NameAndFlags.size() > 1)
172+
SR.NewFlags = parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
169173

170174
return SR;
171175
}
172176

177+
static SectionFlagsUpdate parseSetSectionFlagValue(StringRef FlagValue) {
178+
if (!StringRef(FlagValue).contains('='))
179+
error("Bad format for --set-section-flags: missing '='");
180+
181+
// Initial split: ".foo" = "f1,f2,..."
182+
auto Section2Flags = StringRef(FlagValue).split('=');
183+
SectionFlagsUpdate SFU;
184+
SFU.Name = Section2Flags.first;
185+
186+
// Flags split: "f1" "f2" ...
187+
SmallVector<StringRef, 6> SectionFlags;
188+
Section2Flags.second.split(SectionFlags, ',');
189+
SFU.NewFlags = parseSectionFlagSet(SectionFlags);
190+
191+
return SFU;
192+
}
193+
173194
static const StringMap<MachineInfo> ArchMap{
174195
// Name, {EMachine, 64bit, LittleEndian}
175196
{"aarch64", {ELF::EM_AARCH64, true, true}},
@@ -327,6 +348,24 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
327348
if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
328349
error("Multiple renames of section " + SR.OriginalName);
329350
}
351+
for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
352+
SectionFlagsUpdate SFU = parseSetSectionFlagValue(Arg->getValue());
353+
if (!Config.SetSectionFlags.try_emplace(SFU.Name, SFU).second)
354+
error("--set-section-flags set multiple times for section " + SFU.Name);
355+
}
356+
// Prohibit combinations of --set-section-flags when the section name is used
357+
// by --rename-section, either as a source or a destination.
358+
for (const auto &E : Config.SectionsToRename) {
359+
const SectionRename &SR = E.second;
360+
if (Config.SetSectionFlags.count(SR.OriginalName))
361+
error("--set-section-flags=" + SR.OriginalName +
362+
" conflicts with --rename-section=" + SR.OriginalName + "=" +
363+
SR.NewName);
364+
if (Config.SetSectionFlags.count(SR.NewName))
365+
error("--set-section-flags=" + SR.NewName +
366+
" conflicts with --rename-section=" + SR.OriginalName + "=" +
367+
SR.NewName);
368+
}
330369

331370
for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
332371
Config.ToRemove.push_back(Arg->getValue());

llvm/tools/llvm-objcopy/CopyConfig.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ struct SectionRename {
3737
Optional<uint64_t> NewFlags;
3838
};
3939

40+
struct SectionFlagsUpdate {
41+
StringRef Name;
42+
uint64_t NewFlags;
43+
};
44+
4045
// Configuration for copying/stripping a single file.
4146
struct CopyConfig {
4247
// Main input/output options
@@ -73,6 +78,7 @@ struct CopyConfig {
7378

7479
// Map options
7580
StringMap<SectionRename> SectionsToRename;
81+
StringMap<SectionFlagsUpdate> SetSectionFlags;
7682
StringMap<StringRef> SymbolsToRename;
7783

7884
// Boolean options

llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
7070
return !isDWOSection(Sec);
7171
}
7272

73+
static uint64_t setSectionFlagsPreserveMask(uint64_t OldFlags,
74+
uint64_t NewFlags) {
75+
// Preserve some flags which should not be dropped when setting flags.
76+
// Also, preserve anything OS/processor dependant.
77+
const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
78+
ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
79+
ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
80+
ELF::SHF_TLS | ELF::SHF_INFO_LINK;
81+
return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
82+
}
83+
7384
static ElfType getOutputElfType(const Binary &Bin) {
7485
// Infer output ELF type from the input ELF object
7586
if (isa<ELFObjectFile<ELF32LE>>(Bin))
@@ -484,16 +495,19 @@ static void handleArgs(const CopyConfig &Config, Object &Obj,
484495
if (Iter != Config.SectionsToRename.end()) {
485496
const SectionRename &SR = Iter->second;
486497
Sec.Name = SR.NewName;
487-
if (SR.NewFlags.hasValue()) {
488-
// Preserve some flags which should not be dropped when setting flags.
489-
// Also, preserve anything OS/processor dependant.
490-
const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
491-
ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
492-
ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
493-
ELF::SHF_TLS | ELF::SHF_INFO_LINK;
494-
Sec.Flags = (Sec.Flags & PreserveMask) |
495-
(SR.NewFlags.getValue() & ~PreserveMask);
496-
}
498+
if (SR.NewFlags.hasValue())
499+
Sec.Flags =
500+
setSectionFlagsPreserveMask(Sec.Flags, SR.NewFlags.getValue());
501+
}
502+
}
503+
}
504+
505+
if (!Config.SetSectionFlags.empty()) {
506+
for (auto &Sec : Obj.sections()) {
507+
const auto Iter = Config.SetSectionFlags.find(Sec.Name);
508+
if (Iter != Config.SetSectionFlags.end()) {
509+
const SectionFlagsUpdate &SFU = Iter->second;
510+
Sec.Flags = setSectionFlagsPreserveMask(Sec.Flags, SFU.NewFlags);
497511
}
498512
}
499513
}

llvm/tools/llvm-objcopy/ObjcopyOpts.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ defm add_section
8686
"Make a section named <section> with the contents of <file>.">,
8787
MetaVarName<"section=file">;
8888

89+
defm set_section_flags
90+
: Eq<"set-section-flags",
91+
"Set section flags for a given section. Flags supported for GNU "
92+
"compatibility: alloc, load, noload, readonly, debug, code, data, "
93+
"rom, share, contents, merge, strings.">,
94+
MetaVarName<"section=flag1[,flag2,...]">;
95+
8996
def strip_all
9097
: Flag<["-", "--"], "strip-all">,
9198
HelpText<

0 commit comments

Comments
 (0)