Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -280,9 +280,11 @@ OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags); void addSection(InputSectionBase *C) override; void sortByPriority(); + void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; private: + void reassignOffsets(); std::vector *> Sections; }; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -763,6 +763,18 @@ return V; } +// This function is called after we sort input sections +// to update their offsets. +template void OutputSection::reassignOffsets() { + uintX_t Off = 0; + for (InputSection *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. // For more detail, read the section of the GCC's manual about init_priority. @@ -778,15 +790,57 @@ Sections.clear(); for (Pair &P : V) Sections.push_back(P.second); + reassignOffsets(); +} - // Reassign section addresses. - uintX_t Off = 0; - for (InputSection *S : Sections) { - Off = alignTo(Off, S->getAlign()); - S->OutSecOff = Off; - Off += S->getSize(); - } - this->Header.sh_size = Off; +// Returns true if S matches /crtbegin.?\.o$/. +static bool isCrtbegin(StringRef S) { + if (S.endswith("crtbegin.o")) + return true; + if (!S.endswith(".o") || S.size() < 3) + return false; + return S.drop_back(3).endswith("crtbegin"); +} + +// .ctors and .dtors are sorted by this priority from highest to lowest. +// +// 1. The section was contained in a CRT file. (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". +// +// 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 static bool compCtors( + const InputSection *A, const InputSection *B) { + bool CrtA = isCrtbegin(A->getFile()->getName()); + bool CrtB = isCrtbegin(B->getFile()->getName()); + if (CrtA != CrtB) + return CrtA; + 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 Y.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 void OutputSection::sortCtorsDtors() { + std::stable_sort(Sections.begin(), Sections.end(), compCtors); + reassignOffsets(); } // Returns a VA which a relocatin RI refers to. Used only for local symbols. Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -916,6 +916,12 @@ reinterpret_cast *>(S)->sortByPriority(); } +// Sort input sections by the special rule for .ctors and .dtors. +template static void sortCtorsDtors(OutputSectionBase *S) { + if (S) + reinterpret_cast *>(S)->sortCtorsDtors(); +} + // Create output section objects and add them to OutputSections. template bool Writer::createSections() { OutputSections.push_back(Out::ElfHeader); @@ -966,8 +972,8 @@ // Sort section contents for __attribute__((init_priority(N)). sortByPriority(Out::Dynamic->InitArraySec); sortByPriority(Out::Dynamic->FiniArraySec); - sortByPriority(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC)); - sortByPriority(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC)); + 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 Index: test/ELF/ctors_dtors_priority.s =================================================================== --- test/ELF/ctors_dtors_priority.s +++ test/ELF/ctors_dtors_priority.s @@ -12,7 +12,7 @@ .byte 1 .section .ctors.100, "aw", @progbits .long 2 -.section .ctors.5, "aw", @progbits +.section .ctors.005, "aw", @progbits .byte 3 .section .ctors, "aw", @progbits .byte 4 @@ -24,7 +24,7 @@ .byte 0x11 .section .dtors.100, "aw", @progbits .long 0x12 -.section .dtors.5, "aw", @progbits +.section .dtors.005, "aw", @progbits .byte 0x13 .section .dtors, "aw", @progbits .byte 0x14