[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:
George Rimar 2016-07-28 21:51:30 +00:00
parent fd5a7f1891
commit 0659800ef0
4 changed files with 90 additions and 36 deletions

View File

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

View File

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

View File

@ -0,0 +1,2 @@
.section .foo,"a"
.quad 0x11

View File

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