ELF: Implement __attribute__((init_priority(N)) support.
authorRui Ueyama <ruiu@google.com>
Wed, 10 Feb 2016 23:20:42 +0000 (23:20 +0000)
committerRui Ueyama <ruiu@google.com>
Wed, 10 Feb 2016 23:20:42 +0000 (23:20 +0000)
llvm-svn: 260460

lld/ELF/OutputSections.cpp
lld/ELF/OutputSections.h
lld/ELF/Writer.cpp
lld/test/ELF/init_fini_priority.s [new file with mode: 0644]

index 86c45bf..c1a05ac 100644 (file)
@@ -750,6 +750,44 @@ void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
   this->Header.sh_size = Off;
 }
 
+// If an input string is in the form of "foo.N" where N is a number,
+// return N. Otherwise, returns 65536, which is one greater than the
+// lowest priority.
+static int getPriority(StringRef S) {
+  size_t Pos = S.rfind('.');
+  if (Pos == StringRef::npos)
+    return 65536;
+  int V;
+  if (S.substr(Pos + 1).getAsInteger(10, V))
+    return 65536;
+  return V;
+}
+
+// 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.
+// For more detail, read the section of the GCC's manual about init_priority.
+template <class ELFT> void OutputSection<ELFT>::sortByPriority() {
+  // Sort sections by priority.
+  typedef std::pair<int, InputSection<ELFT> *> Pair;
+  std::vector<Pair> V;
+  for (InputSection<ELFT> *S : Sections)
+    V.push_back({getPriority(S->getSectionName()), S});
+  std::sort(V.begin(), V.end(),
+            [](const Pair &A, const Pair &B) { return A.first < B.first; });
+  Sections.clear();
+  for (Pair &P : V)
+    Sections.push_back(P.second);
+
+  // Reassign section addresses.
+  uintX_t Off = 0;
+  for (InputSection<ELFT> *S : Sections) {
+    Off = alignTo(Off, S->getAlign());
+    S->OutSecOff = Off;
+    Off += S->getSize();
+  }
+  this->Header.sh_size = Off;
+}
+
 // Returns a VA which a relocatin RI refers to. Used only for local symbols.
 // For non-local symbols, use SymbolBody::getVA instead.
 template <class ELFT, bool IsRela>
index 78e66dc..c392b1a 100644 (file)
@@ -279,6 +279,7 @@ public:
   typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
   OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
   void addSection(InputSectionBase<ELFT> *C) override;
+  void sortByPriority();
   void writeTo(uint8_t *Buf) override;
 
 private:
index 4b7118f..92a9890 100644 (file)
@@ -735,6 +735,10 @@ StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const {
     return ".data";
   if (S.startswith(".bss."))
     return ".bss";
+  if (S.startswith(".init_array."))
+    return ".init_array";
+  if (S.startswith(".fini_array."))
+    return ".fini_array";
   return S;
 }
 
@@ -915,6 +919,13 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
       Symtab.addAbsolute("end", ElfSym<ELFT>::End);
 }
 
+// Sort input sections by section name suffixes for
+// __attribute__((init_priority(N))).
+template <class ELFT> static void sortByPriority(OutputSectionBase<ELFT> *S) {
+  if (S)
+    reinterpret_cast<OutputSection<ELFT> *>(S)->sortByPriority();
+}
+
 // Create output section objects and add them to OutputSections.
 template <class ELFT> bool Writer<ELFT>::createSections() {
   OutputSections.push_back(Out<ELFT>::ElfHeader);
@@ -962,6 +973,10 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
   Out<ELFT>::Dynamic->FiniArraySec =
       Factory.lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC);
 
+  // Sort section contents for __attribute__((init_priority(N)).
+  sortByPriority(Out<ELFT>::Dynamic->InitArraySec);
+  sortByPriority(Out<ELFT>::Dynamic->FiniArraySec);
+
   // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
   // symbols for sections, so that the runtime can get the start and end
   // addresses of each section by section name. Add such symbols.
diff --git a/lld/test/ELF/init_fini_priority.s b/lld/test/ELF/init_fini_priority.s
new file mode 100644 (file)
index 0000000..d46ae6f
--- /dev/null
@@ -0,0 +1,29 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t.exe
+// RUN: llvm-objdump -s %t.exe | FileCheck %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  nop
+
+.section .init_array, "aw", @init_array
+  .align 8
+  .byte 1
+.section .init_array.100, "aw", @init_array
+  .long 2
+.section .init_array.5, "aw", @init_array
+  .byte 3
+
+.section .fini_array, "aw", @fini_array
+  .align 8
+  .byte 4
+.section .fini_array.100, "aw", @fini_array
+  .long 5
+.section .fini_array.5, "aw", @fini_array
+  .byte 6
+
+// CHECK:      Contents of section .init_array:
+// CHECK-NEXT: 03020000 00000000 01
+// CHECK:      Contents of section .fini_array:
+// CHECK-NEXT: 06050000 00000000 04