Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -1053,6 +1053,8 @@ if (Config->GcSections) markLive(); decompressAndMergeSections(); + if (!Script->Opt.HasSections) + createInitFiniSynthetics(); if (Config->ICF) doIcf(); Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -141,7 +141,6 @@ uint32_t getFiller(); void sort(std::function Order); - void sortInitFini(); void sortCtorsDtors(); }; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -229,19 +229,6 @@ return false; } -// 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 (!to_integer(S.substr(Pos + 1), V, 10)) - return 65536; - return V; -} - // A helper function for the SORT() command. static std::function getComparator(SortSectionPolicy K) { @@ -1009,17 +996,6 @@ 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 -// because the compiler keeps the original initialization order in a -// translation unit and we need to respect that. -// For more detail, read the section of the GCC's manual about init_priority. -void OutputSectionCommand::sortInitFini() { - // Sort sections by priority. - sort([](InputSectionBase *S) { return getPriority(S->Name); }); -} - uint32_t OutputSectionCommand::getFiller() { if (Filler) return *Filler; Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -656,6 +656,23 @@ std::vector Sections; }; +// InitFiniSection is a class holding .init_array and .fini_array sections. +// For such sections sorting rules are special, see finalizeContents() member. +template class InitFiniSection final : public SyntheticSection { +public: + InitFiniSection(StringRef Name, uint32_t Type, uint64_t Flags, + uint32_t Alignment) + : SyntheticSection(Flags, Type, Alignment, Name) {} + void addSection(InputSection *S) { Sections.push_back(S); } + void writeTo(uint8_t *Buf) override; + void finalizeContents() override; + size_t getSize() const override { return Size; } + +private: + uint64_t Size = 0; + std::vector Sections; +}; + // .MIPS.abiflags section. template class MipsAbiFlagsSection final : public SyntheticSection { @@ -749,6 +766,8 @@ InputSection *createInterpSection(); template MergeInputSection *createCommentSection(); void decompressAndMergeSections(); +template void createInitFiniSynthetics(); +int getPriority(StringRef S); SymbolBody *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, uint64_t Size, InputSectionBase *Section); Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -2222,6 +2222,39 @@ return Builder.getSize(); } +template void InitFiniSection::writeTo(uint8_t *Buf) { + for (InputSection *S : Sections) + S->writeTo(Buf); +} + +// 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 +// because the compiler keeps the original initialization order in a +// translation unit and we need to respect that. +// For more detail, read the section of the GCC's manual about init_priority. +template void InitFiniSection::finalizeContents() { + auto Cmp = [](const InputSection *A, const InputSection *B) { + return getPriority(A->Name) < getPriority(B->Name); + }; + std::stable_sort(Sections.begin(), Sections.end(), Cmp); + + uint64_t Off = 0; + for (InputSection *Sec : Sections) { + Off = alignTo(Size, Sec->Alignment); + Sec->OutSecOff = Off; + Size = Off + Sec->getSize(); + Alignment = std::max(Alignment, Sec->Alignment); + } +} + +template static void finalizeAndClean(ArrayRef Sections) { + for (auto *Sec : Sections) + Sec->finalizeContents(); + std::vector &V = InputSections; + V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); +} + // This function decompresses compressed sections and scans over the input // sections to create mergeable synthetic sections. It removes // MergeInputSections from the input section array and adds new synthetic @@ -2271,11 +2304,48 @@ } (*I)->addSection(MS); } - for (auto *MS : MergeSections) - MS->finalizeContents(); - std::vector &V = InputSections; - V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); + finalizeAndClean(MergeSections); +} + +template void elf::createInitFiniSynthetics() { + std::vector *> InitFiniSections; + for (InputSectionBase *&S : InputSections) { + if (S->Type != SHT_INIT_ARRAY && S->Type != SHT_FINI_ARRAY) + continue; + + StringRef OutsecName = getOutputSectionName(S->Name); + uint64_t Flags = S->Flags & ~(uint64_t)SHF_GROUP; + auto I = llvm::find_if(InitFiniSections, [=](InitFiniSection *Sec) { + return Sec->Name == OutsecName && Sec->Flags == Flags; + }); + + if (I == InitFiniSections.end()) { + InitFiniSection *Syn = make>( + OutsecName, S->Type, Flags, 0 /*Alignment*/); + InitFiniSections.push_back(Syn); + Syn->addSection(cast(S)); + S = Syn; + } else { + (*I)->addSection(cast(S)); + S = nullptr; + } + } + + finalizeAndClean>(InitFiniSections); +} + +// 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. +int elf::getPriority(StringRef S) { + size_t Pos = S.rfind('.'); + if (Pos == StringRef::npos) + return 65536; + int V; + if (!to_integer(S.substr(Pos + 1), V, 10)) + return 65536; + return V; } MipsRldMapSection::MipsRldMapSection() @@ -2378,6 +2448,11 @@ template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); +template void elf::createInitFiniSynthetics(); +template void elf::createInitFiniSynthetics(); +template void elf::createInitFiniSynthetics(); +template void elf::createInitFiniSynthetics(); + template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; @@ -2437,3 +2512,8 @@ template class elf::EhFrameSection; template class elf::EhFrameSection; template class elf::EhFrameSection; + +template class elf::InitFiniSection; +template class elf::InitFiniSection; +template class elf::InitFiniSection; +template class elf::InitFiniSection; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -866,13 +866,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) @@ -939,8 +932,6 @@ Script->fabricateDefaultCommands(); sortBySymbolsOrder(); - sortInitFini(findSectionCommand(".init_array")); - sortInitFini(findSectionCommand(".fini_array")); sortCtorsDtors(findSectionCommand(".ctors")); sortCtorsDtors(findSectionCommand(".dtors")); }