[lld] r260620 - ELF: Implement the correct semantics of .[cd]tors.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 11 15:41:38 PST 2016


Author: ruiu
Date: Thu Feb 11 17:41:38 2016
New Revision: 260620

URL: http://llvm.org/viewvc/llvm-project?rev=260620&view=rev
Log:
ELF: Implement the correct semantics of .[cd]tors.

As I noted in the comment, the sorting order of .[cd]tors are
different from .{init,fini}_array's.

http://reviews.llvm.org/D17120

Added:
    lld/trunk/test/ELF/Inputs/ctors_dtors_priority1.s
    lld/trunk/test/ELF/Inputs/ctors_dtors_priority2.s
    lld/trunk/test/ELF/Inputs/ctors_dtors_priority3.s
Modified:
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/ctors_dtors_priority.s

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=260620&r1=260619&r2=260620&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Feb 11 17:41:38 2016
@@ -763,10 +763,25 @@ static int getPriority(StringRef S) {
   return V;
 }
 
+// This function is called after we sort input sections
+// to update their offsets.
+template <class ELFT> void OutputSection<ELFT>::reassignOffsets() {
+  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;
+}
+
 // 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>::sortByPriority() {
+template <class ELFT> void OutputSection<ELFT>::sortInitFini() {
   // Sort sections by priority.
   typedef std::pair<int, InputSection<ELFT> *> Pair;
   auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
@@ -778,15 +793,68 @@ template <class ELFT> void OutputSection
   Sections.clear();
   for (Pair &P : V)
     Sections.push_back(P.second);
+  reassignOffsets();
+}
 
-  // 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 true if S matches /Filename.?\.o$/.
+static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
+  if (!S.endswith(".o"))
+    return false;
+  S = S.drop_back(2);
+  if (S.endswith(Filename))
+    return true;
+  return !S.empty() && S.drop_back().endswith(Filename);
+}
+
+static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
+static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
+
+// .ctors and .dtors are sorted by this priority from highest to lowest.
+//
+//  1. The section was contained in crtbegin (crtbegin contains
+//     some sentinel value in its .ctors and .dtors so that the runtime
+//     can find the beginning of the sections.)
+//
+//  2. The section has an optional priority value in the form of ".ctors.N"
+//     or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
+//     they are compared as string rather than number.
+//
+//  3. The section is just ".ctors" or ".dtors".
+//
+//  4. The section was contained in crtend, which contains an end marker.
+//
+// In an ideal world, we don't need this function because .init_array and
+// .ctors are duplicate features (and .init_array is newer.) However, there
+// are too many real-world use cases of .ctors, so we had no choice to
+// support that with this rather ad-hoc semantics.
+template <class ELFT>
+static bool compCtors(const InputSection<ELFT> *A,
+                      const InputSection<ELFT> *B) {
+  bool BeginA = isCrtbegin(A->getFile()->getName());
+  bool BeginB = isCrtbegin(B->getFile()->getName());
+  if (BeginA != BeginB)
+    return BeginA;
+  bool EndA = isCrtend(A->getFile()->getName());
+  bool EndB = isCrtend(B->getFile()->getName());
+  if (EndA != EndB)
+    return EndB;
+  StringRef X = A->getSectionName();
+  StringRef Y = B->getSectionName();
+  assert(X.startswith(".ctors") || X.startswith(".dtors"));
+  assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
+  X = X.substr(6);
+  Y = Y.substr(6);
+  if (X.empty() || Y.empty())
+    return X.empty();
+  return X < Y;
+}
+
+// Sorts input sections by the special rules for .ctors and .dtors.
+// Unfortunately, the rules are different from the one for .{init,fini}_array.
+// Read the comment above.
+template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
+  std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
+  reassignOffsets();
 }
 
 // Returns a VA which a relocatin RI refers to. Used only for local symbols.

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=260620&r1=260619&r2=260620&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Feb 11 17:41:38 2016
@@ -279,10 +279,12 @@ 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 sortInitFini();
+  void sortCtorsDtors();
   void writeTo(uint8_t *Buf) override;
 
 private:
+  void reassignOffsets();
   std::vector<InputSection<ELFT> *> Sections;
 };
 

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=260620&r1=260619&r2=260620&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Feb 11 17:41:38 2016
@@ -897,9 +897,15 @@ template <class ELFT> void Writer<ELFT>:
 
 // Sort input sections by section name suffixes for
 // __attribute__((init_priority(N))).
-template <class ELFT> static void sortByPriority(OutputSectionBase<ELFT> *S) {
+template <class ELFT> static void sortInitFini(OutputSectionBase<ELFT> *S) {
   if (S)
-    reinterpret_cast<OutputSection<ELFT> *>(S)->sortByPriority();
+    reinterpret_cast<OutputSection<ELFT> *>(S)->sortInitFini();
+}
+
+// Sort input sections by the special rule for .ctors and .dtors.
+template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) {
+  if (S)
+    reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
 }
 
 // Create output section objects and add them to OutputSections.
@@ -950,10 +956,10 @@ template <class ELFT> bool Writer<ELFT>:
       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);
-  sortByPriority(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
-  sortByPriority(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
+  sortInitFini(Out<ELFT>::Dynamic->InitArraySec);
+  sortInitFini(Out<ELFT>::Dynamic->FiniArraySec);
+  sortCtorsDtors(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
+  sortCtorsDtors(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
 
   // 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

Added: lld/trunk/test/ELF/Inputs/ctors_dtors_priority1.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/ctors_dtors_priority1.s?rev=260620&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/ctors_dtors_priority1.s (added)
+++ lld/trunk/test/ELF/Inputs/ctors_dtors_priority1.s Thu Feb 11 17:41:38 2016
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .byte 0xA1
+
+.section .dtors, "aw", @progbits
+  .byte 0xA2

Added: lld/trunk/test/ELF/Inputs/ctors_dtors_priority2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/ctors_dtors_priority2.s?rev=260620&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/ctors_dtors_priority2.s (added)
+++ lld/trunk/test/ELF/Inputs/ctors_dtors_priority2.s Thu Feb 11 17:41:38 2016
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .byte 0xB1
+
+.section .dtors, "aw", @progbits
+  .byte 0xB2

Added: lld/trunk/test/ELF/Inputs/ctors_dtors_priority3.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/ctors_dtors_priority3.s?rev=260620&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/ctors_dtors_priority3.s (added)
+++ lld/trunk/test/ELF/Inputs/ctors_dtors_priority3.s Thu Feb 11 17:41:38 2016
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .byte 0xC1
+
+.section .dtors, "aw", @progbits
+  .byte 0xC2

Modified: lld/trunk/test/ELF/ctors_dtors_priority.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ctors_dtors_priority.s?rev=260620&r1=260619&r2=260620&view=diff
==============================================================================
--- lld/trunk/test/ELF/ctors_dtors_priority.s (original)
+++ lld/trunk/test/ELF/ctors_dtors_priority.s Thu Feb 11 17:41:38 2016
@@ -1,5 +1,11 @@
-// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-// RUN: ld.lld %t -o %t.exe
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority1.s -o %t-crtbegin.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority2.s -o %t2
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority3.s -o %t-crtend.o
+// RUN: ld.lld %t1 %t2 %t-crtend.o %t-crtbegin.o -o %t.exe
 // RUN: llvm-objdump -s %t.exe | FileCheck %s
 // REQUIRES: x86
 
@@ -8,11 +14,10 @@ _start:
   nop
 
 .section .ctors, "aw", @progbits
-  .align 8
   .byte 1
 .section .ctors.100, "aw", @progbits
-  .long 2
-.section .ctors.5, "aw", @progbits
+  .byte 2
+.section .ctors.005, "aw", @progbits
   .byte 3
 .section .ctors, "aw", @progbits
   .byte 4
@@ -20,11 +25,10 @@ _start:
   .byte 5
 
 .section .dtors, "aw", @progbits
-  .align 8
   .byte 0x11
 .section .dtors.100, "aw", @progbits
-  .long 0x12
-.section .dtors.5, "aw", @progbits
+  .byte 0x12
+.section .dtors.005, "aw", @progbits
   .byte 0x13
 .section .dtors, "aw", @progbits
   .byte 0x14
@@ -32,6 +36,6 @@ _start:
   .byte 0x15
 
 // CHECK:      Contents of section .ctors:
-// CHECK-NEXT: 03020000 00000000 010405
+// CHECK-NEXT: a1b10104 050302c1
 // CHECK:      Contents of section .dtors:
-// CHECK-NEXT: 13120000 00000000 111415
+// CHECK-NEXT: a2b21114 151312c2




More information about the llvm-commits mailing list