Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -85,6 +85,7 @@ InputSectionDescription() : BaseCommand(InputSectionKind) {} static bool classof(const BaseCommand *C); StringRef FilePattern; + bool Sort = false; std::vector ExcludedFiles; std::vector SectionPatterns; }; @@ -135,7 +136,7 @@ bool hasPhdrsCommands(); private: - std::vector> + std::vector>>> getSectionMap(); std::vector *> Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -74,21 +74,14 @@ return false; } -// Create a vector of (, ). -// For example, if a returned vector contains (".text" (".foo.*" ".bar.*")), -// input sections start with ".foo." or ".bar." should be added to -// ".text" section. +// Create a vector of (, list of ). template -std::vector> +std::vector>>> LinkerScript::getSectionMap() { - std::vector> Ret; - + std::vector>>> Ret; for (const std::unique_ptr &Base1 : Opt.Commands) if (auto *Cmd1 = dyn_cast(Base1.get())) - for (const std::unique_ptr &Base2 : Cmd1->Commands) - if (auto *Cmd2 = dyn_cast(Base2.get())) - Ret.emplace_back(Cmd1->Name, Cmd2); - + Ret.emplace_back(Cmd1->Name, Cmd1->Commands); return Ret; } @@ -120,32 +113,55 @@ return Ret; } +// Add input section to output section. If there is no output section yet, +// then create it and add to output section list. +template +static void addSection(OutputSectionFactory &Factory, + std::vector *> &Out, + InputSectionBase *C, StringRef Name) { + OutputSectionBase *Sec; + bool IsNew; + std::tie(Sec, IsNew) = Factory.create(C, Name); + if (IsNew) + Out.push_back(Sec); + Sec->addSection(C); +} + +template +static void mayBeSort(std::vector *> &S, bool Sort) { + if (Sort) + std::stable_sort(S.begin(), S.end(), + [](InputSectionBase *A, InputSectionBase *B) { + return A->getSectionName() < B->getSectionName(); + }); +} + template std::vector *> LinkerScript::createSections(OutputSectionFactory &Factory) { std::vector *> Ret; - // Add input section to output section. If there is no output section yet, - // then create it and add to output section list. - auto Add = [&](InputSectionBase *C, StringRef Name) { - OutputSectionBase *Sec; - bool IsNew; - std::tie(Sec, IsNew) = Factory.create(C, Name); - if (IsNew) - Ret.push_back(Sec); - Sec->addSection(C); - }; - for (auto &P : getSectionMap()) { StringRef OutputName = P.first; - const InputSectionDescription *I = P.second; - for (InputSectionBase *S : getInputSections(I)) { - if (OutputName == "/DISCARD/") { - S->Live = false; - reportDiscarded(S); + ArrayRef> &Commands = P.second; + + for (const std::unique_ptr &Cmd : Commands) { + auto *InCmd = dyn_cast(Cmd.get()); + if (!InCmd) continue; + + std::vector *> Candidates; + for (InputSectionBase *S : getInputSections(InCmd)) { + if (OutputName == "/DISCARD/") { + S->Live = false; + reportDiscarded(S); + continue; + } + Candidates.push_back(S); } - Add(S, OutputName); + mayBeSort(Candidates, InCmd->Sort); + for (InputSectionBase *I : Candidates) + addSection(Factory, Ret, I, OutputName); } } @@ -154,7 +170,7 @@ Symtab::X->getObjectFiles()) for (InputSectionBase *S : F->getSections()) if (!isDiscarded(S) && !S->OutSec) - Add(S, getOutputSectionName(S)); + addSection(Factory, Ret, S, getOutputSectionName(S)); // Remove from the output all the sections which did not meet // the optional constraints. @@ -449,6 +465,7 @@ void readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionPhdrs(); std::unique_ptr readInputSectionDescription(); + void readInputFilePattern(InputSectionDescription *InCmd, bool Keep); void readInputSectionRules(InputSectionDescription *InCmd, bool Keep); unsigned readPhdrType(); void readProvide(bool Hidden); @@ -679,7 +696,17 @@ .Default(-1); } -void ScriptParser::readInputSectionRules(InputSectionDescription *InCmd, bool Keep) { +void ScriptParser::readInputFilePattern(InputSectionDescription *InCmd, + bool Keep) { + while (!Error && !skip(")")) { + if (Keep) + Opt.KeptSections.push_back(peek()); + InCmd->SectionPatterns.push_back(next()); + } +} + +void ScriptParser::readInputSectionRules(InputSectionDescription *InCmd, + bool Keep) { InCmd->FilePattern = next(); expect("("); @@ -689,11 +716,15 @@ InCmd->ExcludedFiles.push_back(next()); } - while (!Error && !skip(")")) { - if (Keep) - Opt.KeptSections.push_back(peek()); - InCmd->SectionPatterns.push_back(next()); + if (skip("SORT")) { + expect("("); + InCmd->Sort = true; + readInputFilePattern(InCmd, Keep); + expect(")"); + return; } + + readInputFilePattern(InCmd, Keep); } std::unique_ptr Index: test/ELF/linkerscript/Inputs/linkerscript-sort.s =================================================================== --- test/ELF/linkerscript/Inputs/linkerscript-sort.s +++ test/ELF/linkerscript/Inputs/linkerscript-sort.s @@ -0,0 +1,14 @@ +.section .aaa.5, "a" +.quad 0x55 + +.section .aaa.1, "a" +.quad 0x11 + +.section .aaa.3, "a" +.quad 0x33 + +.section .aaa.2, "a" +.quad 0x22 + +.section .aaa.4, "a" +.quad 0x44 Index: test/ELF/linkerscript/linkerscript-sort.s =================================================================== --- test/ELF/linkerscript/linkerscript-sort.s +++ test/ELF/linkerscript/linkerscript-sort.s @@ -0,0 +1,61 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +# RUN: %p/Inputs/linkerscript-sort.s -o %t2.o + +# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t1.script +# RUN: ld.lld -o %t1 --script %t1.script %t2.o %t1.o +# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=UNSORTED %s +# UNSORTED: Contents of section .aaa: +# UNSORTED-NEXT: 0120 55000000 00000000 11000000 00000000 +# UNSORTED-NEXT: 0130 33000000 00000000 22000000 00000000 +# UNSORTED-NEXT: 0140 44000000 00000000 05000000 00000000 +# UNSORTED-NEXT: 0150 01000000 00000000 03000000 00000000 +# UNSORTED-NEXT: 0160 02000000 00000000 04000000 00000000 + +## Check that SORT works (sorted by name of section). +# RUN: echo "SECTIONS { .aaa : { *(SORT(.aaa.*)) } }" > %t2.script +# RUN: ld.lld -o %t2 --script %t2.script %t2.o %t1.o +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SORTED_A %s +# SORTED_A: Contents of section .aaa: +# SORTED_A-NEXT: 0120 11000000 00000000 01000000 00000000 +# SORTED_A-NEXT: 0130 22000000 00000000 02000000 00000000 +# SORTED_A-NEXT: 0140 33000000 00000000 03000000 00000000 +# SORTED_A-NEXT: 0150 44000000 00000000 04000000 00000000 +# SORTED_A-NEXT: 0160 55000000 00000000 05000000 00000000 + +## When we switch the order of files, check that sorting by +## section names is stable. +# RUN: echo "SECTIONS { .aaa : { *(SORT(.aaa.*)) } }" > %t3.script +# RUN: ld.lld -o %t3 --script %t3.script %t1.o %t2.o +# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_B %s +# SORTED_B: Contents of section .aaa: +# SORTED_B-NEXT: 0120 01000000 00000000 11000000 00000000 +# SORTED_B-NEXT: 0130 02000000 00000000 22000000 00000000 +# SORTED_B-NEXT: 0140 03000000 00000000 33000000 00000000 +# SORTED_B-NEXT: 0150 04000000 00000000 44000000 00000000 +# SORTED_B-NEXT: 0160 05000000 00000000 55000000 00000000 + +## Check that SORT surrounded with KEEP also works. +# RUN: echo "SECTIONS { .aaa : { KEEP (*(SORT(.aaa.*))) } }" > %t3.script +# RUN: ld.lld -o %t3 --script %t3.script %t2.o %t1.o +# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_A %s + +.global _start +_start: + nop + +.section .aaa.5, "a" +.quad 5 + +.section .aaa.1, "a" +.quad 1 + +.section .aaa.3, "a" +.quad 3 + +.section .aaa.2, "a" +.quad 2 + +.section .aaa.4, "a" +.quad 4