forked from OSchip/llvm-project
[ELF] - Linkerscript: implemented filename specification.
Scripts can contain something like: KEEP (*crtbegin.o(.ctors)) What means that "*crtbegin.o" is a wildcard of file to take the sections from. This is some kind of opposite to EXCLUDE_FILE and used in FreeBSD script: https://svnweb.freebsd.org/base/head/sys/conf/ldscript.amd64?revision=284870&view=markup#l122 Patch implements this. Differential revision: https://reviews.llvm.org/D22852 llvm-svn: 277042
This commit is contained in:
parent
fd5a7f1891
commit
0659800ef0
|
@ -92,20 +92,27 @@ LinkerScript<ELFT>::getSectionMap() {
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool fileMatches(const InputSectionDescription *Desc,
|
||||||
|
StringRef Filename) {
|
||||||
|
if (!globMatch(Desc->FilePattern, Filename))
|
||||||
|
return false;
|
||||||
|
return Desc->ExcludedFiles.empty() || !match(Desc->ExcludedFiles, Filename);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns input sections filtered by given glob patterns.
|
// Returns input sections filtered by given glob patterns.
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
std::vector<InputSectionBase<ELFT> *>
|
std::vector<InputSectionBase<ELFT> *>
|
||||||
LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I) {
|
LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I) {
|
||||||
ArrayRef<StringRef> Patterns = I->Patterns;
|
ArrayRef<StringRef> Patterns = I->SectionPatterns;
|
||||||
ArrayRef<StringRef> ExcludedFiles = I->ExcludedFiles;
|
|
||||||
std::vector<InputSectionBase<ELFT> *> Ret;
|
std::vector<InputSectionBase<ELFT> *> Ret;
|
||||||
for (const std::unique_ptr<ObjectFile<ELFT>> &F :
|
for (const std::unique_ptr<ObjectFile<ELFT>> &F :
|
||||||
Symtab<ELFT>::X->getObjectFiles())
|
Symtab<ELFT>::X->getObjectFiles()) {
|
||||||
for (InputSectionBase<ELFT> *S : F->getSections())
|
if (fileMatches(I, sys::path::filename(F->getName())))
|
||||||
if (!isDiscarded(S) && !S->OutSec && match(Patterns, S->getSectionName()))
|
for (InputSectionBase<ELFT> *S : F->getSections())
|
||||||
if (ExcludedFiles.empty() ||
|
if (!isDiscarded(S) && !S->OutSec &&
|
||||||
!match(ExcludedFiles, sys::path::filename(F->getName())))
|
match(Patterns, S->getSectionName()))
|
||||||
Ret.push_back(S);
|
Ret.push_back(S);
|
||||||
|
}
|
||||||
|
|
||||||
if ((llvm::find(Patterns, "COMMON") != Patterns.end()))
|
if ((llvm::find(Patterns, "COMMON") != Patterns.end()))
|
||||||
Ret.push_back(CommonInputSection<ELFT>::X);
|
Ret.push_back(CommonInputSection<ELFT>::X);
|
||||||
|
@ -428,9 +435,7 @@ private:
|
||||||
void readAsNeeded();
|
void readAsNeeded();
|
||||||
void readEntry();
|
void readEntry();
|
||||||
void readExtern();
|
void readExtern();
|
||||||
std::unique_ptr<InputSectionDescription> readFilePattern();
|
|
||||||
void readGroup();
|
void readGroup();
|
||||||
void readKeep(OutputSectionCommand *Cmd);
|
|
||||||
void readInclude();
|
void readInclude();
|
||||||
void readNothing() {}
|
void readNothing() {}
|
||||||
void readOutput();
|
void readOutput();
|
||||||
|
@ -443,6 +448,8 @@ private:
|
||||||
SymbolAssignment *readAssignment(StringRef Name);
|
SymbolAssignment *readAssignment(StringRef Name);
|
||||||
void readOutputSectionDescription(StringRef OutSec);
|
void readOutputSectionDescription(StringRef OutSec);
|
||||||
std::vector<StringRef> readOutputSectionPhdrs();
|
std::vector<StringRef> readOutputSectionPhdrs();
|
||||||
|
std::unique_ptr<InputSectionDescription> readInputSectionDescription();
|
||||||
|
void readInputSectionRules(InputSectionDescription *InCmd, bool Keep);
|
||||||
unsigned readPhdrType();
|
unsigned readPhdrType();
|
||||||
void readProvide(bool Hidden);
|
void readProvide(bool Hidden);
|
||||||
void readAlign(OutputSectionCommand *Cmd);
|
void readAlign(OutputSectionCommand *Cmd);
|
||||||
|
@ -672,32 +679,38 @@ static int precedence(StringRef Op) {
|
||||||
.Default(-1);
|
.Default(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<InputSectionDescription> ScriptParser::readFilePattern() {
|
void ScriptParser::readInputSectionRules(InputSectionDescription *InCmd, bool Keep) {
|
||||||
expect("*");
|
InCmd->FilePattern = next();
|
||||||
expect("(");
|
expect("(");
|
||||||
|
|
||||||
auto InCmd = llvm::make_unique<InputSectionDescription>();
|
|
||||||
|
|
||||||
if (skip("EXCLUDE_FILE")) {
|
if (skip("EXCLUDE_FILE")) {
|
||||||
expect("(");
|
expect("(");
|
||||||
while (!Error && !skip(")"))
|
while (!Error && !skip(")"))
|
||||||
InCmd->ExcludedFiles.push_back(next());
|
InCmd->ExcludedFiles.push_back(next());
|
||||||
InCmd->Patterns.push_back(next());
|
|
||||||
expect(")");
|
|
||||||
} else {
|
|
||||||
while (!Error && !skip(")"))
|
|
||||||
InCmd->Patterns.push_back(next());
|
|
||||||
}
|
}
|
||||||
return InCmd;
|
|
||||||
|
while (!Error && !skip(")")) {
|
||||||
|
if (Keep)
|
||||||
|
Opt.KeptSections.push_back(peek());
|
||||||
|
InCmd->SectionPatterns.push_back(next());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptParser::readKeep(OutputSectionCommand *Cmd) {
|
std::unique_ptr<InputSectionDescription>
|
||||||
expect("(");
|
ScriptParser::readInputSectionDescription() {
|
||||||
std::unique_ptr<InputSectionDescription> InCmd = readFilePattern();
|
auto InCmd = std::make_unique<InputSectionDescription>();
|
||||||
Opt.KeptSections.insert(Opt.KeptSections.end(), InCmd->Patterns.begin(),
|
|
||||||
InCmd->Patterns.end());
|
// Input section wildcard can be surrounded by KEEP.
|
||||||
Cmd->Commands.push_back(std::move(InCmd));
|
// https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
|
||||||
expect(")");
|
if (skip("KEEP")) {
|
||||||
|
expect("(");
|
||||||
|
readInputSectionRules(InCmd.get(), true);
|
||||||
|
expect(")");
|
||||||
|
} else {
|
||||||
|
readInputSectionRules(InCmd.get(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InCmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptParser::readAlign(OutputSectionCommand *Cmd) {
|
void ScriptParser::readAlign(OutputSectionCommand *Cmd) {
|
||||||
|
@ -734,16 +747,13 @@ void ScriptParser::readOutputSectionDescription(StringRef OutSec) {
|
||||||
expect("{");
|
expect("{");
|
||||||
|
|
||||||
while (!Error && !skip("}")) {
|
while (!Error && !skip("}")) {
|
||||||
|
if ((!peek().empty() && peek()[0] == '*') || peek() == "KEEP") {
|
||||||
|
Cmd->Commands.push_back(readInputSectionDescription());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
StringRef Tok = next();
|
StringRef Tok = next();
|
||||||
if (Tok == "*") {
|
if (Tok == "PROVIDE") {
|
||||||
auto *InCmd = new InputSectionDescription();
|
|
||||||
Cmd->Commands.emplace_back(InCmd);
|
|
||||||
expect("(");
|
|
||||||
while (!Error && !skip(")"))
|
|
||||||
InCmd->Patterns.push_back(next());
|
|
||||||
} else if (Tok == "KEEP") {
|
|
||||||
readKeep(Cmd);
|
|
||||||
} else if (Tok == "PROVIDE") {
|
|
||||||
readProvide(false);
|
readProvide(false);
|
||||||
} else if (Tok == "PROVIDE_HIDDEN") {
|
} else if (Tok == "PROVIDE_HIDDEN") {
|
||||||
readProvide(true);
|
readProvide(true);
|
||||||
|
|
|
@ -84,8 +84,9 @@ struct OutputSectionCommand : BaseCommand {
|
||||||
struct InputSectionDescription : BaseCommand {
|
struct InputSectionDescription : BaseCommand {
|
||||||
InputSectionDescription() : BaseCommand(InputSectionKind) {}
|
InputSectionDescription() : BaseCommand(InputSectionKind) {}
|
||||||
static bool classof(const BaseCommand *C);
|
static bool classof(const BaseCommand *C);
|
||||||
|
StringRef FilePattern;
|
||||||
std::vector<StringRef> ExcludedFiles;
|
std::vector<StringRef> ExcludedFiles;
|
||||||
std::vector<StringRef> Patterns;
|
std::vector<StringRef> SectionPatterns;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PhdrsCommand {
|
struct PhdrsCommand {
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
.section .foo,"a"
|
||||||
|
.quad 0x11
|
|
@ -0,0 +1,41 @@
|
||||||
|
# REQUIRES: x86
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfirst.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
|
||||||
|
# RUN: %p/Inputs/linkerscript-filename-spec.s -o %tsecond.o
|
||||||
|
|
||||||
|
# RUN: echo "SECTIONS { .foo : { \
|
||||||
|
# RUN: KEEP(*first.o(.foo)) \
|
||||||
|
# RUN: KEEP(*second.o(.foo)) } }" > %t1.script
|
||||||
|
# RUN: ld.lld -o %t1 --script %t1.script %tfirst.o %tsecond.o
|
||||||
|
# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTSECOND %s
|
||||||
|
# FIRSTSECOND: Contents of section .foo:
|
||||||
|
# FIRSTSECOND-NEXT: 0120 01000000 00000000 11000000 00000000
|
||||||
|
|
||||||
|
# RUN: echo "SECTIONS { .foo : { \
|
||||||
|
# RUN: KEEP(*second.o(.foo)) \
|
||||||
|
# RUN: KEEP(*first.o(.foo)) } }" > %t2.script
|
||||||
|
# RUN: ld.lld -o %t2 --script %t2.script %tfirst.o %tsecond.o
|
||||||
|
# RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SECONDFIRST %s
|
||||||
|
# SECONDFIRST: Contents of section .foo:
|
||||||
|
# SECONDFIRST-NEXT: 0120 11000000 00000000 01000000 00000000
|
||||||
|
|
||||||
|
## Now the same tests but without KEEP. Checking that file name inside
|
||||||
|
## KEEP is parsed fine.
|
||||||
|
# RUN: echo "SECTIONS { .foo : { \
|
||||||
|
# RUN: *first.o(.foo) \
|
||||||
|
# RUN: *second.o(.foo) } }" > %t3.script
|
||||||
|
# RUN: ld.lld -o %t3 --script %t3.script %tfirst.o %tsecond.o
|
||||||
|
# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTSECOND %s
|
||||||
|
|
||||||
|
# RUN: echo "SECTIONS { .foo : { \
|
||||||
|
# RUN: *second.o(.foo) \
|
||||||
|
# RUN: *first.o(.foo) } }" > %t4.script
|
||||||
|
# RUN: ld.lld -o %t4 --script %t4.script %tfirst.o %tsecond.o
|
||||||
|
# RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=SECONDFIRST %s
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
nop
|
||||||
|
|
||||||
|
.section .foo,"a"
|
||||||
|
.quad 1
|
Loading…
Reference in New Issue