Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -29,12 +29,12 @@ // This class represents each rule in SECTIONS command. struct SectionRule { - SectionRule(StringRef D, StringRef S) - : Dest(D), SectionPattern(S) {} + SectionRule(StringRef D, StringRef S, unsigned O) + : Dest(D), SectionPattern(S), InputOrder(O) {} StringRef Dest; - StringRef SectionPattern; + unsigned InputOrder; }; // This enum represents what we can observe in SECTIONS tag of script: @@ -75,7 +75,7 @@ typedef typename ELFT::uint uintX_t; public: - StringRef getOutputSection(InputSectionBase *S); + std::pair getOutputSection(InputSectionBase *S); ArrayRef getFiller(StringRef Name); bool isDiscarded(InputSectionBase *S); bool shouldKeep(InputSectionBase *S); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -186,16 +186,17 @@ uint64_t ExprParser::parseExpr() { return parseExpr1(parsePrimary(), 0); } template -StringRef LinkerScript::getOutputSection(InputSectionBase *S) { +std::pair +LinkerScript::getOutputSection(InputSectionBase *S) { for (SectionRule &R : Opt.Sections) if (globMatch(R.SectionPattern, S->getSectionName())) - return R.Dest; - return ""; + return std::make_pair(R.Dest, R.InputOrder); + return std::pair("", UINT_MAX); } template bool LinkerScript::isDiscarded(InputSectionBase *S) { - return getOutputSection(S) == "/DISCARD/"; + return getOutputSection(S).first == "/DISCARD/"; } template @@ -510,6 +511,7 @@ } void ScriptParser::readOutputSectionDescription() { + unsigned Order = 0; StringRef OutSec = next(); Opt.Commands.push_back({SectionKind, {}, OutSec}); expect(":"); @@ -520,20 +522,21 @@ if (Tok == "*") { expect("("); while (!Error && !skip(")")) - Opt.Sections.emplace_back(OutSec, next()); + Opt.Sections.emplace_back(OutSec, next(), Order); } else if (Tok == "KEEP") { expect("("); expect("*"); expect("("); while (!Error && !skip(")")) { StringRef Sec = next(); - Opt.Sections.emplace_back(OutSec, Sec); + Opt.Sections.emplace_back(OutSec, Sec, Order); Opt.KeptSections.push_back(Sec); } expect(")"); } else { setError("unknown command " + Tok); } + Order++; } StringRef Tok = peek(); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -75,7 +75,8 @@ void writeSections(); void writeBuildId(); bool isDiscarded(InputSectionBase *IS) const; - StringRef getOutputSectionName(InputSectionBase *S) const; + StringRef getOutputSectionName(InputSectionBase *S, + unsigned &InputOrder) const; bool needsInterpSection() const { return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty(); } @@ -505,12 +506,14 @@ } template -StringRef Writer::getOutputSectionName(InputSectionBase *S) const { - StringRef Dest = Script::X->getOutputSection(S); - if (!Dest.empty()) - return Dest; +StringRef Writer::getOutputSectionName(InputSectionBase *S, + unsigned &InputOrder) const { + StringRef Name; + std::tie(Name, InputOrder) = Script::X->getOutputSection(S); + if (!Name.empty()) + return Name; - StringRef Name = S->getSectionName(); + Name = S->getSectionName(); for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata."}) @@ -716,6 +719,13 @@ // Create output section objects and add them to OutputSections. template void Writer::createSections() { + struct InOutOrder { + InputSectionBase *In; + OutputSectionBase *Out; + unsigned Order; + }; + std::vector InOutMap; + // Add .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. if (needsInterpSection()) @@ -739,16 +749,30 @@ } OutputSectionBase *Sec; bool IsNew; - std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C)); + unsigned InputOrder; + std::tie(Sec, IsNew) = + Factory.create(C, getOutputSectionName(C, InputOrder)); if (IsNew) { OwningSections.emplace_back(Sec); OutputSections.push_back(Sec); RegularSections.push_back(Sec); } - Sec->addSection(C); + if (ScriptConfig->DoLayout) + InOutMap.push_back({C, Sec, InputOrder}); + else + Sec->addSection(C); } } + if (!InOutMap.empty()) { + std::stable_sort(InOutMap.begin(), InOutMap.end(), + [](const InOutOrder &v1, const InOutOrder &v2) { + return v1.Order < v2.Order; + }); + std::for_each(InOutMap.begin(), InOutMap.end(), + [](const InOutOrder &v) { v.Out->addSection(v.In); }); + } + // If we have a .opd section (used under PPC64 for function descriptors), // store a pointer to it here so that we can use it later when processing // relocations. Index: test/ELF/linkerscript-input-order.s =================================================================== --- test/ELF/linkerscript-input-order.s +++ test/ELF/linkerscript-input-order.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: echo "SECTIONS { . = 0x1000; .foo : {*(.foo.*) *(.bar.*) } }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -section=.foo -s %t1 > %t.output + +# RUN: echo "SECTIONS { . = 0x1000; .foo : {*(.foo.* .bar.*)} }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -section=.foo -s %t1 >> %t.output +# RUN: cat %t.output | FileCheck %s + +# CHECK: Contents of section .foo: +# CHECK-NEXT: 1000 00000000 00000000 ffffffff eeeeeeee +# CHECK: Contents of section .foo: +# CHECK-NEXT: 1000 ffffffff 00000000 eeeeeeee 00000000 + +.global _start +_start: + nop + +.section .bar.1,"a" +bar1: + .long 0xFFFFFFFF + +.section .foo.1,"a" +foo1: + .long 0 + +.section .bar.2,"a" +bar2: + .long 0xEEEEEEEE + +.section .foo.2,"a" +foo2: + .long 0