Index: lld/trunk/ELF/LinkerScript.h =================================================================== --- lld/trunk/ELF/LinkerScript.h +++ lld/trunk/ELF/LinkerScript.h @@ -99,6 +99,7 @@ // 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(Re1)), @@ -107,10 +108,14 @@ 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 @@ 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. Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -156,10 +156,10 @@ }); } -static void sortSections(std::vector &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 *F : Symtab::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::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 readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); Regex readFilePatterns(); - void readSectionExcludes(InputSectionDescription *Cmd); + std::vector 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 ScriptParser::readInputSectionsList() { + std::vector 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 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(); + } + + for (SectionPattern &Pat : V) { + Pat.SortInner = Inner; + Pat.SortOuter = Outer; } - expect(")"); - return Cmd; - } - readSectionExcludes(Cmd); + std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns)); + } return Cmd; } Index: lld/trunk/test/ELF/linkerscript/sort2.s =================================================================== --- lld/trunk/test/ELF/linkerscript/sort2.s +++ lld/trunk/test/ELF/linkerscript/sort2.s @@ -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