Index: lld/ELF/LinkerScript.cpp =================================================================== --- lld/ELF/LinkerScript.cpp +++ lld/ELF/LinkerScript.cpp @@ -949,66 +949,6 @@ ISD->Sections.push_back(P.second); } -// 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 OutputSectionCommand::sortCtorsDtors() { - assert(Commands.size() == 1); - auto *ISD = cast(Commands[0]); - std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors); -} - // 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 Index: lld/ELF/SyntheticSections.h =================================================================== --- lld/ELF/SyntheticSections.h +++ lld/ELF/SyntheticSections.h @@ -133,6 +133,18 @@ uint64_t Size = 0; }; +class InitFiniSection : public SyntheticSection { +public: + static InitFiniSection *create(InputSection *CtorsDtors); + void writeTo(uint8_t *) override; + bool empty() const override { return Contents.empty(); } + size_t getSize() const override { return Contents.size(); } + +private: + InitFiniSection(uint32_t Type, StringRef Name, std::vector Contents); + std::vector Contents; +}; + // .note.gnu.build-id section. class BuildIdSection : public SyntheticSection { // First 16 bytes are a header. Index: lld/ELF/SyntheticSections.cpp =================================================================== --- lld/ELF/SyntheticSections.cpp +++ lld/ELF/SyntheticSections.cpp @@ -319,6 +319,65 @@ } } +// 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"); } + +static StringRef toInitFiniName(StringRef S) { + if (S.startswith(".ctors")) + return Saver.save(".init_array" + S.substr(6)); + if (S.startswith(".dtors")) + return Saver.save(".fini_array" + S.substr(6)); + llvm_unreachable("bad .ctors/.dtors section"); +} + +template static void reverseCopy(uint8_t *To, ArrayRef From) { + T *Buf = (T *)To; + for (auto Data : llvm::reverse(From)) + *Buf++ = Data; +} + +InitFiniSection *InitFiniSection::create(InputSection *Sec) { + StringRef Name = Sec->Name; + if (Name != ".ctors" || Name != ".dtors" || !Name.startswith(".ctors.") || + !Name.startswith(".dtors.")) + return nullptr; + + StringRef Filename = Sec->File->getName(); + if (isCrtbegin(Filename) || isCrtend(Filename)) + return nullptr; + + std::vector Contents(Sec->Data.size()); + if (Config->Is64) + reverseCopy(Contents.data(), Sec->getDataAs()); + else + reverseCopy(Contents.data(), Sec->getDataAs()); + + auto *Ret = new InitFiniSection(Name.startswith(".ctors") ? SHT_INIT_ARRAY + : SHT_FINI_ARRAY, + toInitFiniName(Name), Contents); + make>(Ret); + return Ret; +} + +InitFiniSection::InitFiniSection(uint32_t Type, StringRef Name, + std::vector Contents) + : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), + Contents(Contents) {} + +void InitFiniSection::writeTo(uint8_t *Buf) { + memcpy(Buf, Contents.data(), Contents.size()); +} + BuildIdSection::BuildIdSection() : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"), HashSize(getHashSize()) {} Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -136,6 +136,14 @@ Phdrs.erase(I, Phdrs.end()); } +template static void convertCtorsDtorsToInitFini() { + for (InputSectionBase *&S : InputSections) + if (InputSection *IS = dyn_cast(S)) + if (IS->Live) + if (InitFiniSection *Sec = InitFiniSection::create(IS)) + S = Sec; +} + template static void combineEhFrameSections() { for (InputSectionBase *&S : InputSections) { EhInputSection *ES = dyn_cast(S); @@ -165,6 +173,9 @@ // Such sections are of type input section. createSyntheticSections(); + // Convert .ctors/.dtors to .init_array/.fini_array. + convertCtorsDtorsToInitFini(); + if (!Config->Relocatable) combineEhFrameSections(); @@ -866,19 +877,6 @@ ElfSym::Edata2 = Add("_edata"); } -// Sort input sections by section name suffixes for -// __attribute__((init_priority(N))). -static void sortInitFini(OutputSectionCommand *Cmd) { - if (Cmd) - Cmd->sortInitFini(); -} - -// Sort input sections by the special rule for .ctors and .dtors. -static void sortCtorsDtors(OutputSectionCommand *Cmd) { - if (Cmd) - Cmd->sortCtorsDtors(); -} - // Sort input sections using the list provided by --symbol-ordering-file. template static void sortBySymbolsOrder() { if (Config->SymbolOrderingFile.empty()) @@ -939,10 +937,13 @@ Script->fabricateDefaultCommands(); sortBySymbolsOrder(); - sortInitFini(findSectionCommand(".init_array")); - sortInitFini(findSectionCommand(".fini_array")); - sortCtorsDtors(findSectionCommand(".ctors")); - sortCtorsDtors(findSectionCommand(".dtors")); + + // Sort input sections by section name suffixes for + // __attribute__((init_priority(N))). + if (OutputSectionCommand *Cmd = findSectionCommand(".init_array")) + Cmd->sortInitFini(); + if (OutputSectionCommand *Cmd = findSectionCommand(".fini_array")) + Cmd->sortInitFini(); } // We want to find how similar two ranks are. 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