[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
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 339c06d..c1c5fa8 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -92,20 +92,27 @@
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.
template <class ELFT>
std::vector<InputSectionBase<ELFT> *>
LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I) {
- ArrayRef<StringRef> Patterns = I->Patterns;
- ArrayRef<StringRef> ExcludedFiles = I->ExcludedFiles;
+ ArrayRef<StringRef> Patterns = I->SectionPatterns;
std::vector<InputSectionBase<ELFT> *> Ret;
for (const std::unique_ptr<ObjectFile<ELFT>> &F :
- Symtab<ELFT>::X->getObjectFiles())
- for (InputSectionBase<ELFT> *S : F->getSections())
- if (!isDiscarded(S) && !S->OutSec && match(Patterns, S->getSectionName()))
- if (ExcludedFiles.empty() ||
- !match(ExcludedFiles, sys::path::filename(F->getName())))
+ Symtab<ELFT>::X->getObjectFiles()) {
+ if (fileMatches(I, sys::path::filename(F->getName())))
+ for (InputSectionBase<ELFT> *S : F->getSections())
+ if (!isDiscarded(S) && !S->OutSec &&
+ match(Patterns, S->getSectionName()))
Ret.push_back(S);
+ }
if ((llvm::find(Patterns, "COMMON") != Patterns.end()))
Ret.push_back(CommonInputSection<ELFT>::X);
@@ -428,9 +435,7 @@
void readAsNeeded();
void readEntry();
void readExtern();
- std::unique_ptr<InputSectionDescription> readFilePattern();
void readGroup();
- void readKeep(OutputSectionCommand *Cmd);
void readInclude();
void readNothing() {}
void readOutput();
@@ -443,6 +448,8 @@
SymbolAssignment *readAssignment(StringRef Name);
void readOutputSectionDescription(StringRef OutSec);
std::vector<StringRef> readOutputSectionPhdrs();
+ std::unique_ptr<InputSectionDescription> readInputSectionDescription();
+ void readInputSectionRules(InputSectionDescription *InCmd, bool Keep);
unsigned readPhdrType();
void readProvide(bool Hidden);
void readAlign(OutputSectionCommand *Cmd);
@@ -672,32 +679,38 @@
.Default(-1);
}
-std::unique_ptr<InputSectionDescription> ScriptParser::readFilePattern() {
- expect("*");
+void ScriptParser::readInputSectionRules(InputSectionDescription *InCmd, bool Keep) {
+ InCmd->FilePattern = next();
expect("(");
- auto InCmd = llvm::make_unique<InputSectionDescription>();
-
if (skip("EXCLUDE_FILE")) {
expect("(");
while (!Error && !skip(")"))
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) {
- expect("(");
- std::unique_ptr<InputSectionDescription> InCmd = readFilePattern();
- Opt.KeptSections.insert(Opt.KeptSections.end(), InCmd->Patterns.begin(),
- InCmd->Patterns.end());
- Cmd->Commands.push_back(std::move(InCmd));
- expect(")");
+std::unique_ptr<InputSectionDescription>
+ScriptParser::readInputSectionDescription() {
+ auto InCmd = std::make_unique<InputSectionDescription>();
+
+ // Input section wildcard can be surrounded by KEEP.
+ // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
+ if (skip("KEEP")) {
+ expect("(");
+ readInputSectionRules(InCmd.get(), true);
+ expect(")");
+ } else {
+ readInputSectionRules(InCmd.get(), false);
+ }
+
+ return InCmd;
}
void ScriptParser::readAlign(OutputSectionCommand *Cmd) {
@@ -734,16 +747,13 @@
expect("{");
while (!Error && !skip("}")) {
+ if ((!peek().empty() && peek()[0] == '*') || peek() == "KEEP") {
+ Cmd->Commands.push_back(readInputSectionDescription());
+ continue;
+ }
+
StringRef Tok = next();
- if (Tok == "*") {
- 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") {
+ if (Tok == "PROVIDE") {
readProvide(false);
} else if (Tok == "PROVIDE_HIDDEN") {
readProvide(true);