Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -82,6 +82,7 @@ struct InputSectionDescription : BaseCommand { InputSectionDescription() : BaseCommand(InputSectionKind) {} static bool classof(const BaseCommand *C); + bool Sort = false; std::vector Patterns; }; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -115,6 +115,7 @@ if (!InCmd) continue; + std::vector *> Candidates; for (ObjectFile &F : Symtab::X->getObjectFiles()) { for (InputSectionBase *S : F->getSections()) { if (isDiscarded(S) || S->OutSec) @@ -124,10 +125,19 @@ if (OutCmd->Name == "/DISCARD/") S->Live = false; else - AddInputSec(S, OutCmd->Name, OutCmd->Constraint); + Candidates.push_back(S); } } } + + if (InCmd->Sort) + std::stable_sort( + Candidates.begin(), Candidates.end(), + [](InputSectionBase *A, InputSectionBase *B) { + return A->getSectionName() < B->getSectionName(); + }); + for (InputSectionBase *I : Candidates) + AddInputSec(I, OutCmd->Name, OutCmd->Constraint); } } @@ -420,6 +430,7 @@ SymbolAssignment *readAssignment(StringRef Name); void readOutputSectionDescription(StringRef OutSec); + void readInputSectionDescription(InputSectionDescription *InCmd, bool Keep); std::vector readOutputSectionPhdrs(); unsigned readPhdrType(); void readProvide(bool Hidden); @@ -648,6 +659,25 @@ .Default(-1); } +void ScriptParser::readInputSectionDescription(InputSectionDescription *InCmd, + bool Keep) { + if (peek() == "SORT") { + expect("SORT"); + expect("("); + InCmd->Sort = true; + readInputSectionDescription(InCmd, Keep); + expect(")"); + return; + } + + + while (!Error && !skip(")")) { + if (Keep) + Opt.KeptSections.push_back(peek()); + InCmd->Patterns.push_back(next()); + } +} + void ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec); Opt.Commands.emplace_back(Cmd); @@ -667,25 +697,30 @@ expect("{"); while (!Error && !skip("}")) { - StringRef Tok = next(); - if (Tok == "*") { + StringRef Peek = peek(); + if (Peek == "*" || Peek == "KEEP") { auto *InCmd = new InputSectionDescription(); Cmd->Commands.emplace_back(InCmd); - expect("("); - while (!Error && !skip(")")) - InCmd->Patterns.push_back(next()); - } else if (Tok == "KEEP") { - expect("("); - expect("*"); - expect("("); - auto *InCmd = new InputSectionDescription(); - Cmd->Commands.emplace_back(InCmd); - while (!Error && !skip(")")) { - Opt.KeptSections.push_back(peek()); - InCmd->Patterns.push_back(next()); + + // Input section wildcard can be surrounded by KEEP. + // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep + if (Peek == "KEEP") { + expect("KEEP"); + expect("("); + expect("*"); + expect("("); + readInputSectionDescription(InCmd, true); + expect(")"); + } else { + expect("*"); + expect("("); + readInputSectionDescription(InCmd, false); } - expect(")"); - } else if (Tok == "PROVIDE") { + continue; + } + + StringRef Tok = next(); + if (Tok == "PROVIDE") { readProvide(false); } else if (Tok == "PROVIDE_HIDDEN") { readProvide(true); Index: test/ELF/linkerscript/linkerscript-sort.s =================================================================== --- test/ELF/linkerscript/linkerscript-sort.s +++ test/ELF/linkerscript/linkerscript-sort.s @@ -0,0 +1,43 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t1.script +# RUN: ld.lld -o %t1 --script %t1.script %t.o +# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=UNSORTED %s +# UNSORTED: Contents of section .aaa: +# UNSORTED-NEXT: 0120 05000000 00000000 01000000 00000000 +# UNSORTED-NEXT: 0130 03000000 00000000 02000000 00000000 +# UNSORTED-NEXT: 0140 04000000 00000000 + +## Check that SORT works. +# RUN: echo "SECTIONS { .aaa : { *(SORT(.aaa.*)) } }" > %t2.script +# RUN: ld.lld -o %t2 --script %t2.script %t.o +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SORTED %s +# SORTED: Contents of section .aaa: +# SORTED-NEXT: 0120 01000000 00000000 02000000 00000000 +# SORTED-NEXT: 0130 03000000 00000000 04000000 00000000 +# SORTED-NEXT: 0140 05000000 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 %t.o +# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED %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