Index: lld/ELF/OutputSections.h =================================================================== --- lld/ELF/OutputSections.h +++ lld/ELF/OutputSections.h @@ -103,7 +103,6 @@ void sort(std::function Order); void sortInitFini(); - void sortCtorsDtors(); private: // Used for implementation of --compress-debug-sections option. Index: lld/ELF/OutputSections.cpp =================================================================== --- lld/ELF/OutputSections.cpp +++ lld/ELF/OutputSections.cpp @@ -493,66 +493,6 @@ Flags |= SHF_INFO_LINK; } -// 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. -static bool compCtors(const InputSection *A, const InputSection *B) { - bool BeginA = isCrtbegin(A->File->getName()); - bool BeginB = isCrtbegin(B->File->getName()); - if (BeginA != BeginB) - return BeginA; - bool EndA = isCrtend(A->File->getName()); - bool EndB = isCrtend(B->File->getName()); - if (EndA != EndB) - return EndB; - StringRef X = A->Name; - StringRef Y = B->Name; - 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 false; - 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. -void OutputSection::sortCtorsDtors() { - assert(SectionCommands.size() == 1); - auto *ISD = cast(SectionCommands[0]); - std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors); -} - // 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. Index: lld/ELF/SyntheticSections.h =================================================================== --- lld/ELF/SyntheticSections.h +++ lld/ELF/SyntheticSections.h @@ -803,6 +803,7 @@ }; template void createCommonSections(); +InputSection *createInitFiniSection(InputSection *Sec); InputSection *createInterpSection(); template MergeInputSection *createCommentSection(); void decompressSections(); Index: lld/ELF/SyntheticSections.cpp =================================================================== --- lld/ELF/SyntheticSections.cpp +++ lld/ELF/SyntheticSections.cpp @@ -81,6 +81,63 @@ } } +template static void reverseCopy(uint8_t *To, ArrayRef From) { + T *Buf = (T *)To; + for (const T &Data : llvm::reverse(From)) + *Buf++ = Data; +} + +// Returns an .{init,fini}_array section name for a given .ctors/.dtors +// section name. For example, it return ".init_array" for ".ctor" and +// ".init_array.10000" for ".ctors.55535". +// +// Section names may include priorities, e.g. .ctors.30 or .init_array.101. +// .ctors.65535 is the highest priority while .init_array.0 is the highest. +// So we need to translate the number. +static StringRef toInitFiniName(StringRef S) { + if (S == ".ctors") + return ".init_array"; + if (S == ".dtors") + return ".fini_array"; + + if (S.startswith(".ctors.")) { + int N = 0; + to_integer(S.substr(7), N, 10); + return Saver.save(".init_array." + Twine(65535 - N)); + } + + if (S.startswith(".dtors.")) { + int N = 0; + to_integer(S.substr(7), N, 10); + return Saver.save(".fini_array." + Twine(65535 - N)); + } + + llvm_unreachable("unexpected section name"); +} + +// Create an .{init,fini}_array section from a given .ctors/.dtors section. +// +// Both types of sections are to call constructors or destructors of +// global objects. .{init,fini}_array are newer, and in most systems, +// they are used exclusively. However, there are still old object files +// out there that contain .ctors/.dtors, so we want to handle them by +// converting them to .init/fini. +InputSection *elf::createInitFiniSection(InputSection *Sec) { + auto *Contents = make>(Sec->Data.size()); + if (Config->Is64) + reverseCopy(Contents->data(), Sec->getDataAs()); + else + reverseCopy(Contents->data(), Sec->getDataAs()); + + uint32_t Type = + Sec->Name.startswith(".ctors") ? SHT_INIT_ARRAY : SHT_FINI_ARRAY; + + auto *Ret = make(SHF_ALLOC, Type, Config->Wordsize, *Contents, + toInitFiniName(Sec->Name)); + Ret->Live = true; + return Ret; +} + // Returns an LLD version string. static ArrayRef getVersion() { // Check LLD_VERSION first for ease of testing. Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -147,6 +147,15 @@ V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } +static void createInitFiniSections() { + for (size_t I = 0; I < InputSections.size(); ++I) + if (InputSection *Sec = dyn_cast(InputSections[I])) + if (Sec->Live) + if (Sec->Name == ".ctors" || Sec->Name.startswith(".ctors.") || + Sec->Name == ".dtors" || Sec->Name.startswith(".dtors.")) + InputSections[I] = createInitFiniSection(Sec); +} + // The main function of the writer. template void Writer::run() { // Create linker-synthesized sections such as .got or .plt. @@ -156,6 +165,9 @@ if (!Config->Relocatable) combineEhFrameSections(); + // Convert .ctors/.dtors sections to .{init,fini}_array sections, if exists. + createInitFiniSections(); + // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) addReservedSymbols(); @@ -825,12 +837,6 @@ Cmd->sortInitFini(); } -// Sort input sections by the special rule for .ctors and .dtors. -static void sortCtorsDtors(OutputSection *Cmd) { - if (Cmd) - Cmd->sortCtorsDtors(); -} - // Sort input sections using the list provided by --symbol-ordering-file. static void sortBySymbolsOrder() { if (Config->SymbolOrderingFile.empty()) @@ -872,8 +878,6 @@ sortBySymbolsOrder(); sortInitFini(findSection(".init_array")); sortInitFini(findSection(".fini_array")); - sortCtorsDtors(findSection(".ctors")); - sortCtorsDtors(findSection(".dtors")); } // This function generates assignments for predefined symbols (e.g. _end or Index: lld/test/ELF/ctors_dtors_priority.s =================================================================== --- lld/test/ELF/ctors_dtors_priority.s +++ lld/test/ELF/ctors_dtors_priority.s @@ -35,14 +35,13 @@ .section .dtors, "aw", @progbits .quad 0x15 -// CHECK: Contents of section .ctors: -// CHECK-NEXT: 202000 a1000000 00000000 01000000 00000000 -// CHECK-NEXT: 202010 04000000 00000000 05000000 00000000 -// CHECK-NEXT: 202020 b1000000 00000000 03000000 00000000 -// CHECK-NEXT: 202030 02000000 00000000 c1000000 00000000 - -// CHECK: Contents of section .dtors: -// CHECK-NEXT: 202040 a2000000 00000000 11000000 00000000 -// CHECK-NEXT: 202050 14000000 00000000 15000000 00000000 -// CHECK-NEXT: 202060 b2000000 00000000 13000000 00000000 -// CHECK-NEXT: 202070 12000000 00000000 c2000000 00000000 +// CHECK: Contents of section .init_array: +// CHECK-NEXT: 200120 02000000 00000000 03000000 00000000 +// CHECK-NEXT: 200130 05000000 00000000 04000000 00000000 +// CHECK-NEXT: 200140 01000000 00000000 b1000000 00000000 +// CHECK-NEXT: 200150 c1000000 00000000 a1000000 00000000 +// CHECK-NEXT: Contents of section .fini_array: +// CHECK-NEXT: 200160 12000000 00000000 13000000 00000000 +// CHECK-NEXT: 200170 15000000 00000000 14000000 00000000 +// CHECK-NEXT: 200180 11000000 00000000 b2000000 00000000 +// CHECK-NEXT: 200190 c2000000 00000000 a2000000 00000000 Index: lld/test/ELF/gc-sections.s =================================================================== --- lld/test/ELF/gc-sections.s +++ lld/test/ELF/gc-sections.s @@ -12,8 +12,6 @@ # NOGC: Name: .text # NOGC: Name: .init # NOGC: Name: .fini -# NOGC: Name: .ctors -# NOGC: Name: .dtors # NOGC: Name: .debug_pubtypes # NOGC: Name: .comment # NOGC: Name: a @@ -27,8 +25,6 @@ # GC1: Name: .text # GC1: Name: .init # GC1: Name: .fini -# GC1: Name: .ctors -# GC1: Name: .dtors # GC1: Name: .debug_pubtypes # GC1: Name: .comment # GC1: Name: a @@ -42,8 +38,6 @@ # GC2: Name: .text # GC2: Name: .init # GC2: Name: .fini -# GC2: Name: .ctors -# GC2: Name: .dtors # GC2: Name: .debug_pubtypes # GC2: Name: .comment # GC2: Name: a