Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -12,6 +12,7 @@ #include "Error.h" #include "ICF.h" #include "InputFiles.h" +#include "InputSection.h" #include "LinkerScript.h" #include "SymbolListFile.h" #include "SymbolTable.h" @@ -507,5 +508,15 @@ markLive(); if (Config->ICF) doIcf(); + + // MergeInputSection::splitIntoPieces needs to be called before + // any call of MergeInputSection::getOffset. Do that. + for (const std::unique_ptr> &F : + Symtab.getObjectFiles()) + for (InputSectionBase *S : F->getSections()) + if (S && S != &InputSection::Discarded && S->Live) + if (auto *MS = dyn_cast>(S)) + MS->splitIntoPieces(); + writeResult(&Symtab); } Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -12,6 +12,7 @@ #include "Config.h" #include "lld/Core/LLVM.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" @@ -171,9 +172,17 @@ public: MergeInputSection(ObjectFile *F, const Elf_Shdr *Header); static bool classof(const InputSectionBase *S); - // Translate an offset in the input section to an offset in the output - // section. + void splitIntoPieces(); + + // Mark the piece at a given offset live. Used by GC. + void markLiveAt(uintX_t Offset) { LiveOffsets.insert(Offset); } + + // Translate an offset in the input section to an offset + // in the output section. uintX_t getOffset(uintX_t Offset); + +private: + llvm::DenseSet LiveOffsets; }; // This corresponds to a .eh_frame section of an input file. Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -501,13 +501,19 @@ template MergeInputSection::MergeInputSection(elf::ObjectFile *F, const Elf_Shdr *Header) - : SplitInputSection(F, Header, InputSectionBase::Merge) { + : SplitInputSection(F, Header, InputSectionBase::Merge) {} + +template void MergeInputSection::splitIntoPieces() { ArrayRef Data = this->getSectionData(); uintX_t EntSize = this->Header->sh_entsize; if (this->Header->sh_flags & SHF_STRINGS) this->Pieces = splitStrings(Data, EntSize); else this->Pieces = splitNonStrings(Data, EntSize); + + if (Config->GcSections) + for (uintX_t Off : LiveOffsets) + this->getSectionPiece(Off)->Live = true; } template Index: ELF/MarkLive.cpp =================================================================== --- ELF/MarkLive.cpp +++ ELF/MarkLive.cpp @@ -141,10 +141,13 @@ auto Enqueue = [&](ResolvedReloc R) { if (!R.Sec) return; - if (auto *MS = dyn_cast>(R.Sec)) { - SectionPiece *Piece = MS->getSectionPiece(R.Offset); - Piece->Live = true; - } + + // Usually, a whole section is marked as live or dead, but in mergeable + // (splittable) sections, each piece of data has independent liveness bit. + // So we explicitly tell it which offset is in use. + if (auto *MS = dyn_cast>(R.Sec)) + MS->markLiveAt(R.Offset); + if (R.Sec->Live) return; R.Sec->Live = true;