ELF: Implement __attribute__((init_priority(N)) support.

llvm-svn: 260460
This commit is contained in:
Rui Ueyama 2016-02-10 23:20:42 +00:00
parent 9ee9fb6571
commit c418570db5
4 changed files with 83 additions and 0 deletions

View 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>

View 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:

View 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.

View File

@ -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