forked from OSchip/llvm-project
[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
This commit is contained in:
parent
1049085c78
commit
07171f21d1
|
@ -156,10 +156,10 @@ static bool matchConstraints(ArrayRef<InputSectionBase<ELFT> *> Sections,
|
|||
});
|
||||
}
|
||||
|
||||
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 @@ void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
|
|||
// 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,7 +180,6 @@ void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
|
|||
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
|
||||
|
@ -192,12 +192,15 @@ void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
|
|||
// --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);
|
||||
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(I->Sections, I->SortInner);
|
||||
sortSections(I->Sections, I->SortOuter);
|
||||
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 @@ private:
|
|||
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 @@ SortSectionPolicy ScriptParser::readSortKind() {
|
|||
// * 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 @@ void ScriptParser::readSectionExcludes(InputSectionDescription *Cmd) {
|
|||
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;
|
||||
while (!HasError && !skip(")")) {
|
||||
SortSectionPolicy Outer = readSortKind();
|
||||
SortSectionPolicy Inner = SortSectionPolicy::Default;
|
||||
std::vector<SectionPattern> V;
|
||||
if (Outer != SortSectionPolicy::Default) {
|
||||
expect("(");
|
||||
SortSectionPolicy K2 = readSortKind();
|
||||
if (K2 != SortSectionPolicy::Default) {
|
||||
Cmd->SortInner = K2;
|
||||
Inner = readSortKind();
|
||||
if (Inner != SortSectionPolicy::Default) {
|
||||
expect("(");
|
||||
Cmd->SectionPatterns.push_back({Regex(), readFilePatterns()});
|
||||
V = readInputSectionsList();
|
||||
expect(")");
|
||||
} else {
|
||||
Cmd->SectionPatterns.push_back({Regex(), readFilePatterns()});
|
||||
V = readInputSectionsList();
|
||||
}
|
||||
expect(")");
|
||||
return Cmd;
|
||||
} else {
|
||||
V = readInputSectionsList();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ struct OutputSectionCommand : BaseCommand {
|
|||
|
||||
// This struct represents one section match pattern in SECTIONS() command.
|
||||
// It can optionally have negative match pattern for EXCLUDED_FILE command.
|
||||
// Also it may be surrounded with SORT() command, so contains sorting rules.
|
||||
struct SectionPattern {
|
||||
SectionPattern(llvm::Regex &&Re1, llvm::Regex &&Re2)
|
||||
: ExcludedFileRe(std::forward<llvm::Regex>(Re1)),
|
||||
|
@ -107,10 +108,14 @@ struct SectionPattern {
|
|||
SectionPattern(SectionPattern &&Other) {
|
||||
std::swap(ExcludedFileRe, Other.ExcludedFileRe);
|
||||
std::swap(SectionRe, Other.SectionRe);
|
||||
std::swap(SortOuter, Other.SortOuter);
|
||||
std::swap(SortInner, Other.SortInner);
|
||||
}
|
||||
|
||||
llvm::Regex ExcludedFileRe;
|
||||
llvm::Regex SectionRe;
|
||||
SortSectionPolicy SortOuter;
|
||||
SortSectionPolicy SortInner;
|
||||
};
|
||||
|
||||
struct InputSectionDescription : BaseCommand {
|
||||
|
@ -119,8 +124,6 @@ struct InputSectionDescription : BaseCommand {
|
|||
FileRe(compileGlobPatterns({FilePattern})) {}
|
||||
static bool classof(const BaseCommand *C);
|
||||
llvm::Regex FileRe;
|
||||
SortSectionPolicy SortOuter = SortSectionPolicy::Default;
|
||||
SortSectionPolicy SortInner = SortSectionPolicy::Default;
|
||||
|
||||
// Input sections that matches at least one of SectionPatterns
|
||||
// will be associated with this InputSectionDescription.
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile1.o
|
||||
|
||||
# RUN: echo "SECTIONS { .abc : { *(SORT(.foo.*) .bar.*) } }" > %t1.script
|
||||
# RUN: ld.lld -o %t1 --script %t1.script %tfile1.o
|
||||
# RUN: llvm-objdump -s %t1 | FileCheck %s
|
||||
|
||||
# CHECK: Contents of section .abc:
|
||||
# CHECK: 00e8 01000000 00000000 02000000 00000000
|
||||
# CHECK: 00f8 03000000 00000000 04000000 00000000
|
||||
# CHECK: 0108 06000000 00000000 05000000 00000000
|
||||
|
||||
# RUN: echo "SECTIONS { \
|
||||
# RUN: .abc : { *(SORT(.foo.* EXCLUDE_FILE (*file1.o) .bar.*) .bar.*) } \
|
||||
# RUN: }" > %t2.script
|
||||
# RUN: ld.lld -o %t2 --script %t2.script %tfile1.o
|
||||
# RUN: llvm-objdump -s %t2 | FileCheck %s
|
||||
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
|
||||
.section .foo.2,"a"
|
||||
.quad 2
|
||||
|
||||
.section .foo.3,"a"
|
||||
.quad 3
|
||||
|
||||
.section .foo.1,"a"
|
||||
.quad 1
|
||||
|
||||
.section .bar.4,"a"
|
||||
.quad 4
|
||||
|
||||
.section .bar.6,"a"
|
||||
.quad 6
|
||||
|
||||
.section .bar.5,"a"
|
||||
.quad 5
|
Loading…
Reference in New Issue