[ELF] - Linkerscript: support complex section pattern grammar.
This is PR30442.
Previously we were failed to parce complex expressions like:
foo : { *(SORT_BY_NAME(bar) zed) }
Main idea of patch that globs and excludes can be wrapped in a SORT.
There is a difference in semanics of ld/gold:
ld likes:
*(SORT(EXCLUDE_FILE (*file1.o) .foo.1))
gold likes:
*(EXCLUDE_FILE (*file1.o) SORT(.foo.1))
Patch implements ld grammar, complex expressions like
next is not a problem anymore:
.abc : { *(SORT(.foo.* EXCLUDE_FILE (*file1.o) .bar.*) .bar.*) }
Differential revision: https://reviews.llvm.org/D24758
llvm-svn: 282078
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 3d1af63..3917c6e 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -156,10 +156,10 @@
});
}
-static void sortSections(std::vector<InputSectionData *> &Sections,
+static void sortSections(InputSectionData **Begin, InputSectionData **End,
SortSectionPolicy K) {
if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)
- std::stable_sort(Sections.begin(), Sections.end(), getComparator(K));
+ std::stable_sort(Begin, End, getComparator(K));
}
// Compute and remember which sections the InputSectionDescription matches.
@@ -168,6 +168,7 @@
// Collects all sections that satisfy constraints of I
// and attach them to I.
for (SectionPattern &Pat : I->SectionPatterns) {
+ size_t SizeBefore = I->Sections.size();
for (ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) {
StringRef Filename = sys::path::filename(F->getName());
if (!I->FileRe.match(Filename) || Pat.ExcludedFileRe.match(Filename))
@@ -179,25 +180,27 @@
if (Pat.SectionRe.match("COMMON"))
I->Sections.push_back(CommonInputSection<ELFT>::X);
}
- }
- // Sort sections as instructed by SORT-family commands and --sort-section
- // option. Because SORT-family commands can be nested at most two depth
- // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command
- // line option is respected even if a SORT command is given, the exact
- // behavior we have here is a bit complicated. Here are the rules.
- //
- // 1. If two SORT commands are given, --sort-section is ignored.
- // 2. If one SORT command is given, and if it is not SORT_NONE,
- // --sort-section is handled as an inner SORT command.
- // 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
- // 4. If no SORT command is given, sort according to --sort-section.
- if (I->SortOuter != SortSectionPolicy::None) {
- if (I->SortInner == SortSectionPolicy::Default)
- sortSections(I->Sections, Config->SortSection);
- else
- sortSections(I->Sections, I->SortInner);
- sortSections(I->Sections, I->SortOuter);
+ // Sort sections as instructed by SORT-family commands and --sort-section
+ // option. Because SORT-family commands can be nested at most two depth
+ // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command
+ // line option is respected even if a SORT command is given, the exact
+ // behavior we have here is a bit complicated. Here are the rules.
+ //
+ // 1. If two SORT commands are given, --sort-section is ignored.
+ // 2. If one SORT command is given, and if it is not SORT_NONE,
+ // --sort-section is handled as an inner SORT command.
+ // 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
+ // 4. If no SORT command is given, sort according to --sort-section.
+ InputSectionData **Begin = I->Sections.data() + SizeBefore;
+ InputSectionData **End = I->Sections.data() + I->Sections.size();
+ if (Pat.SortOuter != SortSectionPolicy::None) {
+ if (Pat.SortInner == SortSectionPolicy::Default)
+ sortSections(Begin, End, Config->SortSection);
+ else
+ sortSections(Begin, End, Pat.SortInner);
+ sortSections(Begin, End, Pat.SortOuter);
+ }
}
// We do not add duplicate input sections, so mark them with a dummy output
@@ -769,7 +772,7 @@
std::vector<StringRef> readOutputSectionPhdrs();
InputSectionDescription *readInputSectionDescription(StringRef Tok);
Regex readFilePatterns();
- void readSectionExcludes(InputSectionDescription *Cmd);
+ std::vector<SectionPattern> readInputSectionsList();
InputSectionDescription *readInputSectionRules(StringRef FilePattern);
unsigned readPhdrType();
SortSectionPolicy readSortKind();
@@ -1072,7 +1075,8 @@
// * Include .foo.1 from every file.
// * Include .foo.2 from every file but a.o
// * Include .foo.3 from every file but b.o
-void ScriptParser::readSectionExcludes(InputSectionDescription *Cmd) {
+std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
+ std::vector<SectionPattern> Ret;
while (!Error && peek() != ")") {
Regex ExcludeFileRe;
if (skip("EXCLUDE_FILE")) {
@@ -1085,38 +1089,49 @@
V.push_back(next());
if (!V.empty())
- Cmd->SectionPatterns.push_back(
- {std::move(ExcludeFileRe), compileGlobPatterns(V)});
+ Ret.push_back({std::move(ExcludeFileRe), compileGlobPatterns(V)});
else
setError("section pattern is expected");
}
- expect(")");
+ return Ret;
}
+// Section pattern grammar can have complex expressions, for example:
+// *(SORT(.foo.* EXCLUDE_FILE (*file1.o) .bar.*) .bar.* SORT(.zed.*))
+// Generally is a sequence of globs and excludes that may be wrapped in a SORT()
+// commands, like: SORT(glob0) glob1 glob2 SORT(glob4)
+// This methods handles wrapping sequences of excluded files and section globs
+// into SORT() if that needed and reads them all.
InputSectionDescription *
ScriptParser::readInputSectionRules(StringRef FilePattern) {
auto *Cmd = new InputSectionDescription(FilePattern);
expect("(");
-
- // Read SORT().
- SortSectionPolicy K1 = readSortKind();
- if (K1 != SortSectionPolicy::Default) {
- Cmd->SortOuter = K1;
- expect("(");
- SortSectionPolicy K2 = readSortKind();
- if (K2 != SortSectionPolicy::Default) {
- Cmd->SortInner = K2;
+ while (!HasError && !skip(")")) {
+ SortSectionPolicy Outer = readSortKind();
+ SortSectionPolicy Inner = SortSectionPolicy::Default;
+ std::vector<SectionPattern> V;
+ if (Outer != SortSectionPolicy::Default) {
expect("(");
- Cmd->SectionPatterns.push_back({Regex(), readFilePatterns()});
+ Inner = readSortKind();
+ if (Inner != SortSectionPolicy::Default) {
+ expect("(");
+ V = readInputSectionsList();
+ expect(")");
+ } else {
+ V = readInputSectionsList();
+ }
expect(")");
} else {
- Cmd->SectionPatterns.push_back({Regex(), readFilePatterns()});
+ V = readInputSectionsList();
}
- expect(")");
- return Cmd;
- }
- readSectionExcludes(Cmd);
+ for (SectionPattern &Pat : V) {
+ Pat.SortInner = Inner;
+ Pat.SortOuter = Outer;
+ }
+
+ std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns));
+ }
return Cmd;
}