Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -106,6 +106,7 @@ StringRef getStringTable() const { return StringTable; } uint32_t getSectionIndex(const Elf_Sym &Sym) const; + uint32_t getSectionIndex(unsigned SymIndex) const; Elf_Sym_Range getElfSymbols(bool OnlyGlobals); @@ -143,6 +144,8 @@ ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; } InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const; + std::vector<InputSectionBase<ELFT> *> + getComdatSections(llvm::DenseSet<StringRef> &Signatures) const; SymbolBody &getSymbolBody(uint32_t SymbolIndex) const { return *SymbolBodies[SymbolIndex]; @@ -153,6 +156,13 @@ return getSymbolBody(SymIndex); } + template <typename RelT> + uint32_t getRelocSectionIndex(const RelT &Rel) const { + return this->getSectionIndex(Rel.getSymbol(Config->Mips64EL)); + } + + StringRef getComdatGroupSignature(unsigned SecIndex); + const Elf_Shdr *getSymbolTable() const { return this->Symtab; }; // Get MIPS GP0 value defined by this file. This value represents the gp value @@ -190,6 +200,9 @@ // MIPS .MIPS.abiflags section defined by this file. std::unique_ptr<MipsAbiFlagsInputSection<ELFT>> MipsAbiFlags; + // Section index to comdat group signature map; + llvm::DenseMap<unsigned, StringRef> SectionGroupSig; + llvm::SpecificBumpPtrAllocator<InputSection<ELFT>> IAlloc; llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc; llvm::SpecificBumpPtrAllocator<EhInputSection<ELFT>> EHAlloc; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -99,6 +99,16 @@ return I; } +template <class ELFT> +uint32_t ELFFileBase<ELFT>::getSectionIndex(unsigned SymIndex) const { + Elf_Sym_Range Syms = ELFObj.symbols(Symtab); + uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); + if (SymIndex >= NumSymbols) + return -1; + + return getSectionIndex(Syms[SymIndex]); +} + template <class ELFT> void ELFFileBase<ELFT>::initStringTable() { if (!Symtab) return; @@ -218,16 +228,20 @@ if (Sections[I] == &InputSection<ELFT>::Discarded) continue; + bool NewGroup; + StringRef GroupSig; switch (Sec.sh_type) { case SHT_GROUP: Sections[I] = &InputSection<ELFT>::Discarded; - if (ComdatGroups.insert(getShtGroupSignature(Sec)).second) - continue; + GroupSig = getShtGroupSignature(Sec); + NewGroup = ComdatGroups.insert(GroupSig).second; for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(getFilename(this) + ": invalid section index in group: " + Twine(SecIndex)); - Sections[SecIndex] = &InputSection<ELFT>::Discarded; + if (!NewGroup) + Sections[SecIndex] = &InputSection<ELFT>::Discarded; + SectionGroupSig[SecIndex] = GroupSig; } break; case SHT_SYMTAB: @@ -368,6 +382,23 @@ } template <class ELFT> +std::vector<InputSectionBase<ELFT> *> elf::ObjectFile<ELFT>::getComdatSections( + DenseSet<StringRef> &Signatures) const { + std::vector<InputSectionBase<ELFT> *> Ret; + for (auto &P : SectionGroupSig) + if (Signatures.find(P.second) != Signatures.end() && + Sections[P.first] != &InputSectionBase<ELFT>::Discarded) + Ret.push_back(Sections[P.first]); + + return Ret; +} + +template <class ELFT> +StringRef elf::ObjectFile<ELFT>::getComdatGroupSignature(unsigned SecIndex) { + return SectionGroupSig[SecIndex]; +} + +template <class ELFT> SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); InputSectionBase<ELFT> *Sec = getSection(*Sym); Index: ELF/MarkLive.cpp =================================================================== --- ELF/MarkLive.cpp +++ ELF/MarkLive.cpp @@ -43,9 +43,12 @@ namespace { // A resolved relocation. The Sec and Offset fields are set if the relocation -// was resolved to an offset within a section. +// was resolved to an offset within a section. If relocation was resolved to +// a member of comdat group then Sec may be null and Offset is an index of +// section in File. template <class ELFT> struct ResolvedReloc { + ObjectFile<ELFT> *File; InputSectionBase<ELFT> *Sec; typename ELFT::uint Offset; }; @@ -70,11 +73,13 @@ SymbolBody &B = Sec.getFile()->getRelocTargetSym(Rel); auto *D = dyn_cast<DefinedRegular<ELFT>>(&B); if (!D || !D->Section) - return {nullptr, 0}; + return {nullptr, nullptr, 0}; + if (D->Section == &InputSectionBase<ELFT>::Discarded) + return {Sec.getFile(), nullptr, Sec.getFile()->getRelocSectionIndex(Rel)}; typename ELFT::uint Offset = D->Value; if (D->isSection()) Offset += getAddend(Sec, Rel); - return {D->Section->Repl, Offset}; + return {D->Section->Repl->getFile(), D->Section->Repl, Offset}; } // Calls Fn for each section that Sec refers to via relocations. @@ -136,7 +141,7 @@ continue; if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR) continue; - Enqueue({R.Sec, 0}); + Enqueue({R.Sec->getFile(), R.Sec, 0}); } } } @@ -187,10 +192,18 @@ // sections to set their "Live" bits. template <class ELFT> void elf::markLive() { SmallVector<InputSection<ELFT> *, 256> Q; + DenseSet<StringRef> LiveComdatGroups; auto Enqueue = [&](ResolvedReloc<ELFT> R) { - if (!R.Sec) + if (!R.Sec) { + if (!R.File) + return; + + StringRef GroupSig = R.File->getComdatGroupSignature(R.Offset); + if (!GroupSig.empty()) + LiveComdatGroups.insert(GroupSig); return; + } // Usually, a whole section is marked as live or dead, but in mergeable // (splittable) sections, each piece of data has independent liveness bit. @@ -207,7 +220,7 @@ auto MarkSymbol = [&](const SymbolBody *Sym) { if (auto *D = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym)) - Enqueue({D->Section, D->Value}); + Enqueue({D->Section->getFile(), D->Section, D->Value}); }; // Add GC root symbols. @@ -235,12 +248,23 @@ if (auto *EH = dyn_cast_or_null<EhInputSection<ELFT>>(Sec)) scanEhFrameSection<ELFT>(*EH, Enqueue); if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec)) - Enqueue({Sec, 0}); + Enqueue({Sec->getFile(), Sec, 0}); } } } - // Mark all reachable sections. + // Pass 1. Mark all reachable sections, except comdat groups. + while (!Q.empty()) + forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue); + + if (LiveComdatGroups.empty()) + return; + + // Pass 2. Identify and mark reachable comdat groups. + for (ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) + for (InputSectionBase<ELFT> *Sec : F->getComdatSections(LiveComdatGroups)) + Enqueue({Sec->getFile(), Sec, 0}); + while (!Q.empty()) forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue); } Index: test/ELF/Inputs/comdat-gc.s =================================================================== --- test/ELF/Inputs/comdat-gc.s +++ test/ELF/Inputs/comdat-gc.s @@ -0,0 +1,10 @@ +.weak _Z3fooIiEvv +.section .text._Z3fooIiEvv,"axG",@progbits,_Z3fooIiEvv,comdat +_Z3fooIiEvv: + ret + +.global _start +.section .zzz, "ax" +_start: + leaq .text._Z3fooIiEvv(%rip), %rax + Index: test/ELF/comdat-gc.s =================================================================== --- test/ELF/comdat-gc.s +++ test/ELF/comdat-gc.s @@ -0,0 +1,13 @@ +// Check that the linker doesn't crash and comdat group is not gc'ed +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/comdat-gc.s -o %t2.o +// RUN: ld.lld --gc-sections %t.o %t2.o -o %t +// RUN: llvm-readobj -t %t | FileCheck %s +// CHECK: _Z3fooIiEvv + +.weak _Z3fooIiEvv + +.section .text._Z3fooIiEvv,"axG",@progbits,_Z3fooIiEvv,comdat +_Z3fooIiEvv: + ret +