[lld] r286440 - [ELF] - Implemented --symbol-ordering-file option.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 10 01:05:21 PST 2016


Author: grimar
Date: Thu Nov 10 03:05:20 2016
New Revision: 286440

URL: http://llvm.org/viewvc/llvm-project?rev=286440&view=rev
Log:
[ELF] - Implemented --symbol-ordering-file option.

Patch allows to pass a symbols file to linker.
LLD will map symbols to sections and sort sections
in output according to symbol ordering file.

That can help to reduce the startup time and/or
amount of pagefaults during startup.

Also, interesting benchmark result was produced by Rafael EspĂ­ndola. 
After applying the symbols file for clang he timed compiling 
X86MCTargetDesc.ii to an object file.  

The page faults went from just
56,988 to 56,946 since most faults are not in the binary.
Running time went from 4.403053515 to 4.178112244. 
The speedup seems to be because of better cache
locality.

Differential revision: https://reviews.llvm.org/D26130

Added:
    lld/trunk/test/ELF/symbol-ordering-file.s
Modified:
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/Options.td
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Thu Nov 10 03:05:20 2016
@@ -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 VersionDefinition {
 struct Configuration {
   InputFile *FirstElf = nullptr;
   uint8_t OSABI = 0;
+  llvm::DenseMap<llvm::CachedHashStringRef, unsigned> SymbolOrderingFile;
   llvm::StringMap<uint64_t> SectionStartMap;
   llvm::StringRef DynamicLinker;
   llvm::StringRef Entry;

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Thu Nov 10 03:05:20 2016
@@ -447,6 +447,18 @@ static SortSectionPolicy getSortKind(opt
   return SortSectionPolicy::Default;
 }
 
+// Parse the --symbol-ordering-file argument. File has form:
+// symbolName1
+// [...]
+// symbolNameN
+static void parseSymbolOrderingList(MemoryBufferRef MB) {
+  unsigned I = 0;
+  SmallVector<StringRef, 0> 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 @@ void LinkerDriver::readConfigs(opt::Inpu
     if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
       parseDynamicList(*Buffer);
 
+  if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
+    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+      parseSymbolOrderingList(*Buffer);
+
   for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
     Config->DynamicList.push_back(Arg->getValue());
 

Modified: lld/trunk/ELF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/Options.td (original)
+++ lld/trunk/ELF/Options.td Thu Nov 10 03:05:20 2016
@@ -177,6 +177,9 @@ def strip_all: F<"strip-all">, HelpText<
 
 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">;

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Nov 10 03:05:20 2016
@@ -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 @@ template <class ELFT> void OutputSection
   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 <class ELFT> void OutputSection<ELFT>::sortInitFini() {
-  // Sort sections by priority.
-  typedef std::pair<int, InputSection<ELFT> *> Pair;
+template <class ELFT>
+void OutputSection<ELFT>::sort(
+    std::function<unsigned(InputSection<ELFT> *S)> Order) {
+  typedef std::pair<unsigned, InputSection<ELFT> *> Pair;
   auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
 
   std::vector<Pair> V;
   for (InputSection<ELFT> *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 <class ELFT> void OutputSection<ELFT>::sortInitFini() {
+  // Sort sections by priority.
+  sort([](InputSection<ELFT> *S) { return getPriority(S->Name); });
+}
+
 // Returns true if S matches /Filename.?\.o$/.
 static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
   if (!S.endswith(".o"))

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Nov 10 03:05:20 2016
@@ -429,6 +429,7 @@ public:
   typedef typename ELFT::uint uintX_t;
   OutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
   void addSection(InputSectionData *C) override;
+  void sort(std::function<unsigned(InputSection<ELFT> *S)> Order);
   void sortInitFini();
   void sortCtorsDtors();
   void writeTo(uint8_t *Buf) override;

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Thu Nov 10 03:05:20 2016
@@ -418,16 +418,6 @@ template <class ELFT> static void addCop
 }
 
 template <class ELFT>
-static StringRef getSymbolName(const elf::ObjectFile<ELFT> &File,
-                               SymbolBody &Body) {
-  if (Body.isLocal() && Body.getNameOffset())
-    return File.getStringTable().data() + Body.getNameOffset();
-  if (!Body.isLocal())
-    return Body.getName();
-  return "";
-}
-
-template <class ELFT>
 static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
                           bool IsWrite, RelExpr Expr, uint32_t Type,
                           const uint8_t *Data) {
@@ -449,7 +439,7 @@ static RelExpr adjustExpr(const elf::Obj
   // 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 @@ std::string getLocation(InputSectionBase
   // Find a symbol at a given location.
   DefinedRegular<ELFT> *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) + ")";
   }
 

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Thu Nov 10 03:05:20 2016
@@ -282,6 +282,14 @@ void elf::printTraceSymbol(Symbol *Sym)
   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<ELF32LE>() const;
 template bool SymbolBody::hasThunk<ELF32BE>() const;
 template bool SymbolBody::hasThunk<ELF64LE>() const;

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Thu Nov 10 03:05:20 2016
@@ -466,6 +466,8 @@ inline Symbol *SymbolBody::symbol() {
                                     offsetof(Symbol, Body));
 }
 
+StringRef getSymbolName(StringRef SymTab, SymbolBody &Body);
+
 } // namespace elf
 } // namespace lld
 

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=286440&r1=286439&r2=286440&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Nov 10 03:05:20 2016
@@ -659,6 +659,38 @@ template <class ELFT> static void sortCt
     reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
 }
 
+// Sort input sections using the list provided by --symbol-ordering-file.
+template <class ELFT>
+static void sortBySymbolsOrder(ArrayRef<OutputSectionBase *> V) {
+  if (Config->SymbolOrderingFile.empty())
+    return;
+
+  // Build sections order map from symbols list.
+  DenseMap<InputSectionBase<ELFT> *, unsigned> SectionsOrder;
+  for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles()) {
+    for (SymbolBody *Body : File->getSymbols()) {
+      auto *D = dyn_cast<DefinedRegular<ELFT>>(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<ELFT> *Sec = dyn_cast<OutputSection<ELFT>>(Base))
+      Sec->sort([&](InputSection<ELFT> *S) {
+        auto It = SectionsOrder.find(S);
+        return It == SectionsOrder.end() ? UINT32_MAX : It->second;
+      });
+}
+
 template <class ELFT>
 void Writer<ELFT>::forEachRelSec(
     std::function<void(InputSectionBase<ELFT> &, const typename ELFT::Shdr &)>
@@ -703,6 +735,7 @@ template <class ELFT> void Writer<ELFT>:
   for (InputSectionBase<ELFT> *IS : Symtab<ELFT>::X->Sections)
     addInputSec(IS);
 
+  sortBySymbolsOrder<ELFT>(OutputSections);
   sortInitFini<ELFT>(findSection(".init_array"));
   sortInitFini<ELFT>(findSection(".fini_array"));
   sortCtorsDtors<ELFT>(findSection(".ctors"));

Added: lld/trunk/test/ELF/symbol-ordering-file.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/symbol-ordering-file.s?rev=286440&view=auto
==============================================================================
--- lld/trunk/test/ELF/symbol-ordering-file.s (added)
+++ lld/trunk/test/ELF/symbol-ordering-file.s Thu Nov 10 03:05:20 2016
@@ -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", at progbits,unique,1
+_foo1:
+ .byte 0x11
+
+.section .foo,"ax", at progbits,unique,2
+_foo2:
+ .byte 0x22
+
+.section .foo,"ax", at progbits,unique,3
+_foo3:
+ .byte 0x33
+
+.section .foo,"ax", at progbits,unique,4
+_foo4:
+ .byte 0x44
+
+.section .foo,"ax", at progbits,unique,5
+_foo5:
+ .byte 0x55
+_bar1:
+ .byte 0x66




More information about the llvm-commits mailing list