Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -16,6 +16,10 @@ #include +namespace llvm { + class Regex; +} + namespace lld { namespace elf { @@ -64,6 +68,13 @@ size_t NameOff; // Offset in string table. }; +// This struct contains list of sections for +// handling --section-ordering-file option. +struct SectionOrdering { + llvm::StringMap SectionNames; + std::vector> SectionRe; +}; + // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. @@ -83,6 +94,7 @@ llvm::StringRef SoName; llvm::StringRef Sysroot; std::string RPath; + std::unique_ptr SectionOrderingFile; std::vector VersionDefinitions; std::vector AuxiliaryList; std::vector DynamicList; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -570,6 +570,10 @@ if (Optional Buffer = readFile(Arg->getValue())) parseDynamicList(*Buffer); + if (auto *Arg = Args.getLastArg(OPT_section_ordering_file)) + if (Optional Buffer = readFile(Arg->getValue())) + parseSectionOrderingList(*Buffer); + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) Config->DynamicList.push_back(Arg->getValue()); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -24,6 +24,7 @@ #include "OutputSections.h" #include "ScriptParser.h" #include "Strings.h" +#include "SymbolListFile.h" #include "Symbols.h" #include "SymbolTable.h" #include "Target.h" @@ -168,6 +169,27 @@ std::stable_sort(Begin, End, getComparator(K)); } +// Sort input sections by order specified in --section-ordering-file. +static void sortSectionsByFileOrder(InputSectionData **Begin, InputSectionData **End) { + typedef std::pair Pair; + if (!Config->SectionOrderingFile) + return; + + // First create the list of sections to sort and get ordering indices. + std::vector> Sorted; + for (InputSectionData **I = Begin; I != End; ++I) + Sorted.push_back({getSectionFileOrder((*I)->Name), *I}); + + // Sort section by order. + auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; + std::stable_sort(Sorted.begin(), Sorted.end(), Comp); + + // Now place the sorted result back. + size_t N = 0; + for (InputSectionData **I = Begin; I != End; ++I, ++N) + *I = Sorted[N].second; +} + // Compute and remember which sections the InputSectionDescription matches. template void LinkerScript::computeInputSections(InputSectionDescription *I) { @@ -187,6 +209,10 @@ I->Sections.push_back(CommonInputSection::X); } + InputSectionData **Begin = I->Sections.data() + SizeBefore; + InputSectionData **End = I->Sections.data() + I->Sections.size(); + sortSectionsByFileOrder(Begin, End); + // 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 @@ -198,8 +224,6 @@ // --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); @@ -240,7 +264,7 @@ } // After we created final list we should now set OutSec pointer to null, - // instead of -1. Otherwise we may get a crash when writing relocs, in + // instead of -1. Otherwise we may get a crash when writing relocs, in // case section is discarded by linker script for (InputSectionBase *S : Ret) S->OutSec = nullptr; Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -155,6 +155,9 @@ def script: S<"script">, HelpText<"Read linker script">; +def section_ordering_file: S<"section-ordering-file">, + HelpText<"Layout sections in the order specified">; + def section_start: S<"section-start">, MetaVarName<"
">, HelpText<"Set address of section">; Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -410,6 +410,7 @@ typedef typename ELFT::uint uintX_t; OutputSection(StringRef Name, uint32_t Type, uintX_t Flags); void addSection(InputSectionBase *C) override; + void sortByOrderList(); void sortInitFini(); void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; @@ -418,6 +419,9 @@ typename Base::Kind getKind() const override { return Base::Regular; } static bool classof(const Base *B) { return B->getKind() == Base::Regular; } std::vector *> Sections; + +private: + void sort(std::function Order); }; template Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -12,6 +12,7 @@ #include "EhFrame.h" #include "LinkerScript.h" #include "Strings.h" +#include "SymbolListFile.h" #include "SymbolTable.h" #include "Target.h" #include "lld/Core/Parallel.h" @@ -915,26 +916,35 @@ this->Header.sh_size = Off; } -// Sorts input sections by section name suffixes, so that .foo.N comes -// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. -// We want to keep the original order if the priorities are the same -// because the compiler keeps the original initialization order in a -// translation unit and we need to respect that. -// For more detail, read the section of the GCC's manual about init_priority. -template void OutputSection::sortInitFini() { - // Sort sections by priority. +template +void OutputSection::sort(std::function Order) { typedef std::pair *> Pair; auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; std::vector V; for (InputSection *S : Sections) - V.push_back({getPriority(S->Name), S}); + V.push_back({Order(S->Name), S}); std::stable_sort(V.begin(), V.end(), Comp); Sections.clear(); for (Pair &P : V) Sections.push_back(P.second); } +// Sort input sections by order specified in --section-ordering-file. +template void OutputSection::sortByOrderList() { + sort(getSectionFileOrder); +} + +// Sorts input sections by section name suffixes, so that .foo.N comes +// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. +// We want to keep the original order if the priorities are the same +// because the compiler keeps the original initialization order in a +// translation unit and we need to respect that. +// For more detail, read the section of the GCC's manual about init_priority. +template void OutputSection::sortInitFini() { + sort(getPriority); +} + // Returns true if S matches /Filename.?\.o$/. static bool isCrtBeginEnd(StringRef S, StringRef Filename) { if (!S.endswith(".o")) Index: ELF/SymbolListFile.h =================================================================== --- ELF/SymbolListFile.h +++ ELF/SymbolListFile.h @@ -18,6 +18,9 @@ void parseDynamicList(MemoryBufferRef MB); +void parseSectionOrderingList(MemoryBufferRef MB); +int getSectionFileOrder(StringRef S); + } // namespace elf } // namespace lld Index: ELF/SymbolListFile.cpp =================================================================== --- ELF/SymbolListFile.cpp +++ ELF/SymbolListFile.cpp @@ -56,3 +56,49 @@ void elf::parseDynamicList(MemoryBufferRef MB) { DynamicListParser(MB.getBuffer()).run(); } + +// Parse the --section-ordering-file argument. File has form: +// +// sectionName1 sectionName2 [...] sectionNameN +// +// Each section name may contain wildcards. + +namespace { +class SectionOrderingListParser final : public ScriptParserBase { +public: + SectionOrderingListParser(StringRef S) : ScriptParserBase(S) {} + void run(); +}; +} // end anonymous namespace + +void SectionOrderingListParser::run() { + Config->SectionOrderingFile.reset(new SectionOrdering()); + + int Priority = 0; + while (!atEOF() && !Error) { + ++Priority; + StringRef S = next(); + if (hasWildcard(S)) + Config->SectionOrderingFile->SectionRe.push_back( + {compileGlobPatterns({S}), Priority}); + else + Config->SectionOrderingFile->SectionNames[S] = Priority; + } +} + +void elf::parseSectionOrderingList(MemoryBufferRef MB) { + SectionOrderingListParser(MB.getBuffer()).run(); +} + +// Search in the file provided by --section-ordering-file for a section position +// index. If the section name matches a glob pattern and a non-glob name, then +// the non-glob position takes precedence. +int elf::getSectionFileOrder(StringRef S) { + auto I = Config->SectionOrderingFile->SectionNames.find(S); + if (I != Config->SectionOrderingFile->SectionNames.end()) + return I->second; + for (std::pair &P : Config->SectionOrderingFile->SectionRe) + if (P.first.match(S)) + return P.second; + return 0; +} Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -668,6 +668,16 @@ reinterpret_cast *>(S)->sortCtorsDtors(); } +// Sort input sections using list provided by --section-ordering-file option. +template +static void sortSectionsByOrder(ArrayRef *> V) { + if (!Config->SectionOrderingFile) + return; + for (OutputSectionBase *Base : V) + if (OutputSection *Sec = dyn_cast>(Base)) + Sec->sortByOrderList(); +} + template void Writer::forEachRelSec( std::function &, const typename ELFT::Shdr &)> @@ -712,6 +722,7 @@ } } + sortSectionsByOrder(OutputSections); sortInitFini(findSection(".init_array")); sortInitFini(findSection(".fini_array")); sortCtorsDtors(findSection(".ctors")); Index: test/ELF/linkerscript/section-ordering-file.s =================================================================== --- test/ELF/linkerscript/section-ordering-file.s +++ test/ELF/linkerscript/section-ordering-file.s @@ -0,0 +1,33 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { . = 0x1000; .text : { *(.text.aaa*) *(.text*) } }" > %t_linker.script + +# RUN: ld.lld --script %t_linker.script %t.o -o %t.out +# RUN: llvm-objdump -s %t.out| FileCheck %s --check-prefix=BEFORE +# BEFORE: Contents of section .text: +# BEFORE-NEXT: 1000 01030200 040506 + +# RUN: echo "*aaa* .text.bbb* .text.aaabbb .text.aaaccc .text.bbbaaa" > %t_order.txt +# RUN: ld.lld --script %t_linker.script --section-ordering-file %t_order.txt %t.o -o %t2.out +# RUN: llvm-objdump -s %t2.out| FileCheck %s --check-prefix=AFTER +# AFTER: Contents of section .text: +# AFTER-NEXT: 1000 01020300 040506 + +.text +.section .text.aaa,"a" +.byte 1 + +.section .text.aaaccc,"a" +.byte 3 + +.section .text.bbb,"a" +.byte 4 + +.section .text.bbbccc,"a" +.byte 5 + +.section .text.bbbaaa,"a" +.byte 6 + +.section .text.aaabbb,"a" +.byte 2 Index: test/ELF/section-ordering-file.s =================================================================== --- test/ELF/section-ordering-file.s +++ test/ELF/section-ordering-file.s @@ -0,0 +1,27 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.out +# RUN: llvm-objdump -s %t.out| FileCheck %s --check-prefix=BEFORE + +# BEFORE: Contents of section .text: +# BEFORE-NEXT: 10120 03040201 + +# RUN: echo "*zed* .text.bar .text.foo* .text.foobar" > %t_order.txt +# RUN: ld.lld --section-ordering-file %t_order.txt %t.o -o %t2.out +# RUN: llvm-objdump -s %t2.out| FileCheck %s --check-prefix=AFTER + +# AFTER: Contents of section .text: +# AFTER-NEXT: 10120 01020304 + +.text +.section .text.foo,"a" +.byte 3 + +.section .text.foobar,"a" +.byte 4 + +.section .text.bar,"a" +.byte 2 + +.section .text.zed,"a" +.byte 1