Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_CONFIG_H #define LLD_ELF_CONFIG_H +#include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ELF.h" @@ -71,6 +72,7 @@ struct Configuration { InputFile *FirstElf = nullptr; uint8_t OSABI = 0; + llvm::DenseMap SymbolOrderingFile; llvm::StringMap SectionStartMap; llvm::StringRef DynamicLinker; llvm::StringRef Entry; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -447,6 +447,18 @@ return SortSectionPolicy::Default; } +// Parse the --symbol-ordering-file argument. File has form: +// symbolName1 +// [...] +// symbolNameN +static void parseSymbolOrderingList(MemoryBufferRef MB) { + unsigned I = 0; + SmallVector Arr; + MB.getBuffer().split(Arr, '\n'); + for (StringRef S : Arr) + Config->SymbolOrderingFile.insert({CachedHashStringRef(S.trim()), I++}); +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -580,6 +592,10 @@ if (Optional Buffer = readFile(Arg->getValue())) parseDynamicList(*Buffer); + if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) + if (Optional Buffer = readFile(Arg->getValue())) + parseSymbolOrderingList(*Buffer); + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) Config->DynamicList.push_back(Arg->getValue()); Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/ELF/Options.td @@ -177,6 +177,9 @@ def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; +def symbol_ordering_file: S<"symbol-ordering-file">, + HelpText<"Layout sections in the order specified by symbol file">; + def sysroot: J<"sysroot=">, HelpText<"Set the system root">; def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">; Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -429,6 +429,7 @@ typedef typename ELFT::uint uintX_t; OutputSection(StringRef Name, uint32_t Type, uintX_t Flags); void addSection(InputSectionData *C) override; + void sort(std::function *S)> Order); void sortInitFini(); void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -14,6 +14,7 @@ #include "LinkerScript.h" #include "Memory.h" #include "Strings.h" +#include "SymbolListFile.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" @@ -978,26 +979,32 @@ this->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. - typedef std::pair *> Pair; +template +void OutputSection::sort( + std::function *S)> 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), S}); std::stable_sort(V.begin(), V.end(), Comp); Sections.clear(); for (Pair &P : V) Sections.push_back(P.second); } +// 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. + sort([](InputSection *S) { return getPriority(S->Name); }); +} + // Returns true if S matches /Filename.?\.o$/. static bool isCrtBeginEnd(StringRef S, StringRef Filename) { if (!S.endswith(".o")) Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -418,16 +418,6 @@ } template -static StringRef getSymbolName(const elf::ObjectFile &File, - SymbolBody &Body) { - if (Body.isLocal() && Body.getNameOffset()) - return File.getStringTable().data() + Body.getNameOffset(); - if (!Body.isLocal()) - return Body.getName(); - return ""; -} - -template static RelExpr adjustExpr(const elf::ObjectFile &File, SymbolBody &Body, bool IsWrite, RelExpr Expr, uint32_t Type, const uint8_t *Data) { @@ -449,7 +439,7 @@ // only memory. We can hack around it if we are producing an executable and // the refered symbol can be preemepted to refer to the executable. if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { - StringRef Name = getSymbolName(File, Body); + StringRef Name = getSymbolName(File.getStringTable(), Body); error("can't create dynamic relocation " + getRelName(Type) + " against " + (Name.empty() ? "readonly segment" : "symbol " + Name)); return Expr; @@ -557,7 +547,7 @@ // Find a symbol at a given location. DefinedRegular *Encl = getSymbolAt(&S, Offset); if (Encl && Encl->Type == STT_FUNC) { - StringRef Func = getSymbolName(*File, *Encl); + StringRef Func = getSymbolName(File->getStringTable(), *Encl); return SrcFile + " (function " + maybeDemangle(Func) + ")"; } Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -466,6 +466,8 @@ offsetof(Symbol, Body)); } +StringRef getSymbolName(StringRef SymTab, SymbolBody &Body); + } // namespace elf } // namespace lld Index: lld/trunk/ELF/Symbols.cpp =================================================================== --- lld/trunk/ELF/Symbols.cpp +++ lld/trunk/ELF/Symbols.cpp @@ -282,6 +282,14 @@ outs() << B->getName() << "\n"; } +StringRef elf::getSymbolName(StringRef SymTab, SymbolBody &Body) { + if (Body.isLocal() && Body.getNameOffset()) + return SymTab.data() + Body.getNameOffset(); + if (!Body.isLocal()) + return Body.getName(); + return ""; +} + template bool SymbolBody::hasThunk() const; template bool SymbolBody::hasThunk() const; template bool SymbolBody::hasThunk() const; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -659,6 +659,38 @@ reinterpret_cast *>(S)->sortCtorsDtors(); } +// Sort input sections using the list provided by --symbol-ordering-file. +template +static void sortBySymbolsOrder(ArrayRef V) { + if (Config->SymbolOrderingFile.empty()) + return; + + // Build sections order map from symbols list. + DenseMap *, unsigned> SectionsOrder; + for (elf::ObjectFile *File : Symtab::X->getObjectFiles()) { + for (SymbolBody *Body : File->getSymbols()) { + auto *D = dyn_cast>(Body); + if (!D || !D->Section) + continue; + StringRef SymName = getSymbolName(File->getStringTable(), *Body); + auto It = Config->SymbolOrderingFile.find(CachedHashString(SymName)); + if (It == Config->SymbolOrderingFile.end()) + continue; + + auto It2 = SectionsOrder.insert({D->Section, It->second}); + if (!It2.second) + It2.first->second = std::min(It->second, It2.first->second); + } + } + + for (OutputSectionBase *Base : V) + if (OutputSection *Sec = dyn_cast>(Base)) + Sec->sort([&](InputSection *S) { + auto It = SectionsOrder.find(S); + return It == SectionsOrder.end() ? UINT32_MAX : It->second; + }); +} + template void Writer::forEachRelSec( std::function &, const typename ELFT::Shdr &)> @@ -703,6 +735,7 @@ for (InputSectionBase *IS : Symtab::X->Sections) addInputSec(IS); + sortBySymbolsOrder(OutputSections); sortInitFini(findSection(".init_array")); sortInitFini(findSection(".fini_array")); sortCtorsDtors(findSection(".ctors")); Index: lld/trunk/test/ELF/symbol-ordering-file.s =================================================================== --- lld/trunk/test/ELF/symbol-ordering-file.s +++ lld/trunk/test/ELF/symbol-ordering-file.s @@ -0,0 +1,44 @@ +# 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 .foo: +# BEFORE-NEXT: 11000 11223344 5566 + +# RUN: echo "_foo4 " > %t_order.txt +# RUN: echo " _foo3" >> %t_order.txt +# RUN: echo "_foo5" >> %t_order.txt +# RUN: echo "_foo2" >> %t_order.txt +# RUN: echo " " >> %t_order.txt +# RUN: echo "_foo4" >> %t_order.txt +# RUN: echo "_bar1" >> %t_order.txt +# RUN: echo "_foo1" >> %t_order.txt + +# RUN: ld.lld --symbol-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 .foo: +# AFTER-NEXT: 11000 44335566 2211 + +.section .foo,"ax",@progbits,unique,1 +_foo1: + .byte 0x11 + +.section .foo,"ax",@progbits,unique,2 +_foo2: + .byte 0x22 + +.section .foo,"ax",@progbits,unique,3 +_foo3: + .byte 0x33 + +.section .foo,"ax",@progbits,unique,4 +_foo4: + .byte 0x44 + +.section .foo,"ax",@progbits,unique,5 +_foo5: + .byte 0x55 +_bar1: + .byte 0x66