[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