ELF: Implement __attribute__((init_priority(N)) support.
llvm-svn: 260460
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 86c45bf..c1a05ac 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -750,6 +750,44 @@
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>
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 78e66dc..c392b1a 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -279,6 +279,7 @@
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:
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 4b7118f..92a9890 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -735,6 +735,10 @@
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 @@
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 @@
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
index 0000000..d46ae6f
--- /dev/null
+++ b/lld/test/ELF/init_fini_priority.s
@@ -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