forked from OSchip/llvm-project
ELF: Change how to handle KEEP linker script command.
You can instruct the linker to not discard sections even if they are unused and --gc-sections option is given. The linker script command for doing that is KEEP. The syntax is KEEP(foo) where foo is a section name. KEEP commands are written in SECTIONS command, so you can specify the order of sections *and* which sections will be kept. Each sub-command in SECTIONS command are translated into SectionRule object. Previously, each SectionRule has `Keep` bit. However, if you think about it, this hid information in too deep in elements of a list. Semantically, KEEP commands aren't really related to SECTIONS subcommands. We can keep the section list for KEEP in a separate list. This patch does that. llvm-svn: 267065
This commit is contained in:
parent
243b71fd8b
commit
8ec77e64fc
|
@ -35,6 +35,8 @@ using namespace lld::elf;
|
||||||
|
|
||||||
ScriptConfiguration *elf::ScriptConfig;
|
ScriptConfiguration *elf::ScriptConfig;
|
||||||
|
|
||||||
|
static bool matchStr(StringRef S, StringRef T);
|
||||||
|
|
||||||
static uint64_t getInteger(StringRef S) {
|
static uint64_t getInteger(StringRef S) {
|
||||||
uint64_t V;
|
uint64_t V;
|
||||||
if (S.getAsInteger(0, V)) {
|
if (S.getAsInteger(0, V)) {
|
||||||
|
@ -159,17 +161,11 @@ static uint64_t evaluate(ArrayRef<StringRef> Tokens, uint64_t Dot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
SectionRule *LinkerScript<ELFT>::find(InputSectionBase<ELFT> *S) {
|
StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) {
|
||||||
for (SectionRule &R : Opt.Sections)
|
for (SectionRule &R : Opt.Sections)
|
||||||
if (R.match(S))
|
if (R.match(S))
|
||||||
return &R;
|
return R.Dest;
|
||||||
return nullptr;
|
return "";
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) {
|
|
||||||
SectionRule *R = find(S);
|
|
||||||
return R ? R->Dest : "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
@ -179,8 +175,10 @@ bool LinkerScript<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) {
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
|
bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
|
||||||
SectionRule *R = find(S);
|
for (StringRef Pat : Opt.KeptSections)
|
||||||
return R && R->Keep;
|
if (matchStr(Pat, S->getSectionName()))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
@ -326,7 +324,7 @@ private:
|
||||||
|
|
||||||
void readLocationCounterValue();
|
void readLocationCounterValue();
|
||||||
void readOutputSectionDescription();
|
void readOutputSectionDescription();
|
||||||
void readSectionPatterns(StringRef OutSec, bool Keep);
|
void readSectionPatterns(StringRef OutSec);
|
||||||
|
|
||||||
const static StringMap<Handler> Cmd;
|
const static StringMap<Handler> Cmd;
|
||||||
ScriptConfiguration &Opt = *ScriptConfig;
|
ScriptConfiguration &Opt = *ScriptConfig;
|
||||||
|
@ -497,10 +495,10 @@ void ScriptParser::readSections() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) {
|
void ScriptParser::readSectionPatterns(StringRef OutSec) {
|
||||||
expect("(");
|
expect("(");
|
||||||
while (!Error && !skip(")"))
|
while (!Error && !skip(")"))
|
||||||
Opt.Sections.emplace_back(OutSec, next(), Keep);
|
Opt.Sections.emplace_back(OutSec, next());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptParser::readLocationCounterValue() {
|
void ScriptParser::readLocationCounterValue() {
|
||||||
|
@ -523,19 +521,28 @@ void ScriptParser::readOutputSectionDescription() {
|
||||||
Opt.Commands.push_back({SectionKind, {}, OutSec});
|
Opt.Commands.push_back({SectionKind, {}, OutSec});
|
||||||
expect(":");
|
expect(":");
|
||||||
expect("{");
|
expect("{");
|
||||||
|
|
||||||
while (!Error && !skip("}")) {
|
while (!Error && !skip("}")) {
|
||||||
StringRef Tok = next();
|
StringRef Tok = next();
|
||||||
if (Tok == "*") {
|
if (Tok == "*") {
|
||||||
readSectionPatterns(OutSec, false);
|
expect("(");
|
||||||
|
while (!Error && !skip(")"))
|
||||||
|
Opt.Sections.emplace_back(OutSec, next());
|
||||||
} else if (Tok == "KEEP") {
|
} else if (Tok == "KEEP") {
|
||||||
expect("(");
|
expect("(");
|
||||||
next(); // Skip *
|
expect("*");
|
||||||
readSectionPatterns(OutSec, true);
|
expect("(");
|
||||||
|
while (!Error && !skip(")")) {
|
||||||
|
StringRef Sec = next();
|
||||||
|
Opt.Sections.emplace_back(OutSec, Sec);
|
||||||
|
Opt.KeptSections.push_back(Sec);
|
||||||
|
}
|
||||||
expect(")");
|
expect(")");
|
||||||
} else {
|
} else {
|
||||||
setError("unknown command " + Tok);
|
setError("unknown command " + Tok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef Tok = peek();
|
StringRef Tok = peek();
|
||||||
if (Tok.startswith("=")) {
|
if (Tok.startswith("=")) {
|
||||||
if (!Tok.startswith("=0x")) {
|
if (!Tok.startswith("=0x")) {
|
||||||
|
|
|
@ -30,17 +30,14 @@ template <class ELFT> class OutputSectionBase;
|
||||||
// This class represents each rule in SECTIONS command.
|
// This class represents each rule in SECTIONS command.
|
||||||
class SectionRule {
|
class SectionRule {
|
||||||
public:
|
public:
|
||||||
SectionRule(StringRef D, StringRef S, bool Keep)
|
SectionRule(StringRef D, StringRef S)
|
||||||
: Dest(D), Keep(Keep), SectionPattern(S) {}
|
: Dest(D), SectionPattern(S) {}
|
||||||
|
|
||||||
// Returns true if S should be in Dest section.
|
// Returns true if S should be in Dest section.
|
||||||
template <class ELFT> bool match(InputSectionBase<ELFT> *S);
|
template <class ELFT> bool match(InputSectionBase<ELFT> *S);
|
||||||
|
|
||||||
StringRef Dest;
|
StringRef Dest;
|
||||||
|
|
||||||
// KEEP command saves unused sections even if --gc-sections is specified.
|
|
||||||
bool Keep = false;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StringRef SectionPattern;
|
StringRef SectionPattern;
|
||||||
};
|
};
|
||||||
|
@ -70,6 +67,10 @@ struct ScriptConfiguration {
|
||||||
bool DoLayout = false;
|
bool DoLayout = false;
|
||||||
|
|
||||||
llvm::BumpPtrAllocator Alloc;
|
llvm::BumpPtrAllocator Alloc;
|
||||||
|
|
||||||
|
// List of section patterns specified with KEEP commands. They will
|
||||||
|
// be kept even if they are unused and --gc-sections is specified.
|
||||||
|
std::vector<StringRef> KeptSections;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ScriptConfiguration *ScriptConfig;
|
extern ScriptConfiguration *ScriptConfig;
|
||||||
|
|
|
@ -37,37 +37,35 @@
|
||||||
# RUN: .keep : { KEEP(*(.keep)) } \
|
# RUN: .keep : { KEEP(*(.keep)) } \
|
||||||
# RUN: .nokeep : { *(.keep) }}" > %t.script
|
# RUN: .nokeep : { *(.keep) }}" > %t.script
|
||||||
# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
|
# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
|
||||||
# RUN: llvm-objdump -section-headers %t1 | \
|
# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED1 %s
|
||||||
# RUN: FileCheck -check-prefix=KEEP-AT-FIRST %s
|
# MIXED1: Sections:
|
||||||
# KEEP-AT-FIRST: Sections:
|
# MIXED1-NEXT: Idx Name Size Address Type
|
||||||
# KEEP-AT-FIRST-NEXT: Idx Name Size Address Type
|
# MIXED1-NEXT: 0 00000000 0000000000000000
|
||||||
# KEEP-AT-FIRST-NEXT: 0 00000000 0000000000000000
|
# MIXED1-NEXT: 1 .keep 00000004 0000000000000120 DATA
|
||||||
# KEEP-AT-FIRST-NEXT: 1 .keep 00000004 0000000000000120 DATA
|
# MIXED1-NEXT: 2 .temp 00000004 0000000000000124 DATA
|
||||||
# KEEP-AT-FIRST-NEXT: 2 .temp 00000004 0000000000000124 DATA
|
# MIXED1-NEXT: 3 .text 00000007 0000000000000128 TEXT DATA
|
||||||
# KEEP-AT-FIRST-NEXT: 3 .text 00000007 0000000000000128 TEXT DATA
|
# MIXED1-NEXT: 4 .symtab 00000060 0000000000000000
|
||||||
# KEEP-AT-FIRST-NEXT: 4 .symtab 00000060 0000000000000000
|
# MIXED1-NEXT: 5 .shstrtab 0000002d 0000000000000000
|
||||||
# KEEP-AT-FIRST-NEXT: 5 .shstrtab 0000002d 0000000000000000
|
# MIXED1-NEXT: 6 .strtab 00000012 0000000000000000
|
||||||
# KEEP-AT-FIRST-NEXT: 6 .strtab 00000012 0000000000000000
|
|
||||||
|
|
||||||
## The same, but now section without KEEP is at first place.
|
## The same, but now section without KEEP is at first place.
|
||||||
## It will be collected then.
|
## gold and bfd linkers disagree here. gold collects .keep while
|
||||||
## This test checks that lld behavior is equal to gold linker.
|
## bfd keeps it. Our current behavior is compatible with bfd although
|
||||||
## ld.bfd has different behavior, it prevents the section .keep
|
## we can choose either way.
|
||||||
## from collecting in this case either.
|
|
||||||
# RUN: echo "SECTIONS { \
|
# RUN: echo "SECTIONS { \
|
||||||
# RUN: .nokeep : { *(.keep) } \
|
# RUN: .nokeep : { *(.keep) } \
|
||||||
# RUN: .keep : { KEEP(*(.keep)) }}" > %t.script
|
# RUN: .keep : { KEEP(*(.keep)) }}" > %t.script
|
||||||
# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
|
# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
|
||||||
# RUN: llvm-objdump -section-headers %t1 | \
|
# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED2 %s
|
||||||
# RUN: FileCheck -check-prefix=KEEP-AT-SECOND %s
|
# MIXED2: Sections:
|
||||||
# KEEP-AT-SECOND: Sections:
|
# MIXED2-NEXT: Idx Name Size Address Type
|
||||||
# KEEP-AT-SECOND-NEXT: Idx Name Size Address Type
|
# MIXED2-NEXT: 0 00000000 0000000000000000
|
||||||
# KEEP-AT-SECOND-NEXT: 0 00000000 0000000000000000
|
# MIXED2-NEXT: 1 .nokeep 00000004 0000000000000120 DATA
|
||||||
# KEEP-AT-SECOND-NEXT: 1 .temp 00000004 0000000000000120 DATA
|
# MIXED2-NEXT: 2 .temp 00000004 0000000000000124 DATA
|
||||||
# KEEP-AT-SECOND-NEXT: 2 .text 00000007 0000000000000124 TEXT DATA
|
# MIXED2-NEXT: 3 .text 00000007 0000000000000128 TEXT DATA
|
||||||
# KEEP-AT-SECOND-NEXT: 3 .symtab 00000048 0000000000000000
|
# MIXED2-NEXT: 4 .symtab 00000060 0000000000000000
|
||||||
# KEEP-AT-SECOND-NEXT: 4 .shstrtab 00000027 0000000000000000
|
# MIXED2-NEXT: 5 .shstrtab 0000002f 0000000000000000
|
||||||
# KEEP-AT-SECOND-NEXT: 5 .strtab 0000000d 0000000000000000
|
# MIXED2-NEXT: 6 .strtab 00000012 0000000000000000
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
|
|
Loading…
Reference in New Issue