diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -97,6 +97,8 @@ Tar = nullptr; memset(&In, 0, sizeof(In)); + SharedFile::VernauxNum = 0; + Config->ProgName = Args[0]; Driver->main(Args); diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -332,6 +332,14 @@ public: // This is actually a vector of Elf_Verdef pointers. std::vector Verdefs; + + // If the output file needs Elf_Verneed data structures for this file, this is + // a vector of Elf_Vernaux version identifiers that map onto the entries in + // Verdefs, otherwise it is empty. + std::vector Vernauxs; + + static unsigned VernauxNum; + std::vector DtNeeded; std::string SoName; @@ -341,18 +349,6 @@ template void parse(); - struct NeededVer { - // The string table offset of the version name in the output file. - size_t StrTab; - - // The version identifier for this version name. - uint16_t Index; - }; - - // Mapping from Elf_Verdef data structures to information about Elf_Vernaux - // data structures in the output file. - std::map VerdefMap; - // Used for --no-allow-shlib-undefined. bool AllNeededIsKnown; diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -869,6 +869,8 @@ return File; } +unsigned SharedFile::VernauxNum; + SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase(SharedKind, M), SoName(DefaultSoName), IsNeeded(!Config->AsNeeded) {} diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -786,37 +786,34 @@ bool isNeeded() const override; }; -class VersionNeedBaseSection : public SyntheticSection { -protected: - // The next available version identifier. - unsigned NextIndex; - -public: - VersionNeedBaseSection(); - virtual void addSymbol(Symbol *Sym) = 0; - virtual size_t getNeedNum() const = 0; -}; - // The .gnu.version_r section defines the version identifiers used by // .gnu.version. It contains a linked list of Elf_Verneed data structures. Each // Elf_Verneed specifies the version requirements for a single DSO, and contains // a reference to a linked list of Elf_Vernaux data structures which define the // mapping from version identifiers to version names. template -class VersionNeedSection final : public VersionNeedBaseSection { +class VersionNeedSection final : public SyntheticSection { using Elf_Verneed = typename ELFT::Verneed; using Elf_Vernaux = typename ELFT::Vernaux; - // A vector of shared files that need Elf_Verneed data structures and the - // string table offsets of their sonames. - std::vector> Needed; + struct Vernaux { + uint64_t Hash; + uint32_t VerneedIndex; + uint64_t NameStrTab; + }; + + struct Verneed { + uint64_t NameStrTab; + std::vector Vernauxs; + }; + + std::vector Verneeds; public: - void addSymbol(Symbol *Sym) override; + VersionNeedSection(); void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; - size_t getNeedNum() const override { return Needed.size(); } bool isNeeded() const override; }; @@ -1061,6 +1058,8 @@ Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, uint64_t Size, InputSectionBase &Section); +void addVerneed(Symbol *SS); + // Linker generated sections which can be used as inputs. struct InStruct { InputSection *ARMAttributes; @@ -1092,7 +1091,7 @@ SymbolTableBaseSection *SymTab; SymtabShndxSection *SymTabShndx; VersionDefinitionSection *VerDef; - VersionNeedBaseSection *VerNeed; + SyntheticSection *VerNeed; VersionTableSection *VerSym; }; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1397,7 +1397,7 @@ if (B->isDefined()) addSym(DT_FINI, B); - bool HasVerNeed = In.VerNeed->getNeedNum() != 0; + bool HasVerNeed = SharedFile::VernauxNum != 0; if (HasVerNeed || In.VerDef) addInSec(DT_VERSYM, In.VerSym); if (In.VerDef) { @@ -1406,7 +1406,11 @@ } if (HasVerNeed) { addInSec(DT_VERNEED, In.VerNeed); - addInt(DT_VERNEEDNUM, In.VerNeed->getNeedNum()); + unsigned NeedNum = 0; + for (SharedFile *F : SharedFiles) + if (!F->Vernauxs.empty()) + ++NeedNum; + addInt(DT_VERNEEDNUM, NeedNum); } if (Config->EMachine == EM_MIPS) { @@ -2780,69 +2784,76 @@ return In.VerDef || In.VerNeed->isNeeded(); } -VersionNeedBaseSection::VersionNeedBaseSection() - : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), - ".gnu.version_r") { - // Identifiers in verneed section start at 2 because 0 and 1 are reserved - // for VER_NDX_LOCAL and VER_NDX_GLOBAL. - // First identifiers are reserved by verdef section if it exist. - NextIndex = getVerDefNum() + 1; -} - -template void VersionNeedSection::addSymbol(Symbol *SS) { +void elf::addVerneed(Symbol *SS) { auto &File = cast(*SS->File); if (SS->VerdefIndex == VER_NDX_GLOBAL) { SS->VersionId = VER_NDX_GLOBAL; return; } - // If we don't already know that we need an Elf_Verneed for this DSO, prepare - // to create one by adding it to our needed list and creating a dynstr entry - // for the soname. - if (File.VerdefMap.empty()) - Needed.push_back({&File, In.DynStrTab->addString(File.SoName)}); - auto *Ver = reinterpret_cast( - File.Verdefs[SS->VerdefIndex]); - typename SharedFile::NeededVer &NV = File.VerdefMap[Ver]; + if (File.Vernauxs.empty()) + File.Vernauxs.resize(File.Verdefs.size()); + + // Select a version identifier for the vernaux data structure, if we haven't + // already allocated one. The verdef identifiers cover the range + // [1..getVerDefNum()]; this causes the vernaux identifiers to start from + // getVerDefNum()+1. + if (File.Vernauxs[SS->VerdefIndex] == 0) + File.Vernauxs[SS->VerdefIndex] = ++SharedFile::VernauxNum + getVerDefNum(); + + SS->VersionId = File.Vernauxs[SS->VerdefIndex]; +} - // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, - // prepare to create one by allocating a version identifier and creating a - // dynstr entry for the version name. - if (NV.Index == 0) { - NV.StrTab = In.DynStrTab->addString(File.getStringTable().data() + - Ver->getAux()->vda_name); - NV.Index = NextIndex++; +template +VersionNeedSection::VersionNeedSection() + : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), + ".gnu.version_r") {} + +template void VersionNeedSection::finalizeContents() { + for (SharedFile *F : SharedFiles) { + if (F->Vernauxs.empty()) + continue; + Verneeds.emplace_back(); + Verneed &VN = Verneeds.back(); + VN.NameStrTab = In.DynStrTab->addString(F->SoName); + for (unsigned I = 0; I != F->Vernauxs.size(); ++I) { + if (F->Vernauxs[I] == 0) + continue; + auto *Verdef = + reinterpret_cast(F->Verdefs[I]); + VN.Vernauxs.push_back( + {Verdef->vd_hash, F->Vernauxs[I], + In.DynStrTab->addString(F->getStringTable().data() + + Verdef->getAux()->vda_name)}); + } } - SS->VersionId = NV.Index; + + if (OutputSection *Sec = In.DynStrTab->getParent()) + getParent()->Link = Sec->SectionIndex; + getParent()->Info = Verneeds.size(); } template void VersionNeedSection::writeTo(uint8_t *Buf) { // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. auto *Verneed = reinterpret_cast(Buf); - auto *Vernaux = reinterpret_cast(Verneed + Needed.size()); + auto *Vernaux = reinterpret_cast(Verneed + Verneeds.size()); - for (std::pair &P : Needed) { + for (auto &VN : Verneeds) { // Create an Elf_Verneed for this DSO. Verneed->vn_version = 1; - Verneed->vn_cnt = P.first->VerdefMap.size(); - Verneed->vn_file = P.second; + Verneed->vn_cnt = VN.Vernauxs.size(); + Verneed->vn_file = VN.NameStrTab; Verneed->vn_aux = reinterpret_cast(Vernaux) - reinterpret_cast(Verneed); Verneed->vn_next = sizeof(Elf_Verneed); ++Verneed; - // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over - // VerdefMap, which will only contain references to needed version - // definitions. Each Elf_Vernaux is based on the information contained in - // the Elf_Verdef in the source DSO. This loop iterates over a std::map of - // pointers, but is deterministic because the pointers refer to Elf_Verdef - // data structures within a single input file. - for (auto &NV : P.first->VerdefMap) { - Vernaux->vna_hash = - reinterpret_cast(NV.first)->vd_hash; + // Create the Elf_Vernauxs for this Elf_Verneed. + for (auto &VNA : VN.Vernauxs) { + Vernaux->vna_hash = VNA.Hash; Vernaux->vna_flags = 0; - Vernaux->vna_other = NV.second.Index; - Vernaux->vna_name = NV.second.StrTab; + Vernaux->vna_other = VNA.VerneedIndex; + Vernaux->vna_name = VNA.NameStrTab; Vernaux->vna_next = sizeof(Elf_Vernaux); ++Vernaux; } @@ -2852,21 +2863,13 @@ Verneed[-1].vn_next = 0; } -template void VersionNeedSection::finalizeContents() { - if (OutputSection *Sec = In.DynStrTab->getParent()) - getParent()->Link = Sec->SectionIndex; - getParent()->Info = Needed.size(); -} - template size_t VersionNeedSection::getSize() const { - unsigned Size = Needed.size() * sizeof(Elf_Verneed); - for (const std::pair &P : Needed) - Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux); - return Size; + return Verneeds.size() * sizeof(Elf_Verneed) + + SharedFile::VernauxNum * sizeof(Elf_Vernaux); } template bool VersionNeedSection::isNeeded() const { - return getNeedNum() != 0; + return SharedFile::VernauxNum != 0; } void MergeSyntheticSection::addSection(MergeInputSection *MS) { diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1647,7 +1647,7 @@ In.DynSymTab->addSymbol(Sym); if (auto *File = dyn_cast_or_null(Sym->File)) if (File->IsNeeded && !Sym->isUndefined()) - In.VerNeed->addSymbol(Sym); + addVerneed(Sym); } } diff --git a/lld/test/ELF/verneed.s b/lld/test/ELF/verneed.s --- a/lld/test/ELF/verneed.s +++ b/lld/test/ELF/verneed.s @@ -68,8 +68,8 @@ # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 00663100 7665726E 65656431 2E736F2E |.f1.verneed1.so.| -# CHECK-NEXT: 0010: 30007633 00663200 76320067 31007665 |0.v3.f2.v2.g1.ve| +# CHECK-NEXT: 0000: 00663100 66320067 31007665 726E6565 |.f1.f2.g1.vernee| +# CHECK-NEXT: 0010: 64312E73 6F2E3000 76320076 33007665 |d1.so.0.v2.v3.ve| # CHECK-NEXT: 0020: 726E6565 64322E73 6F2E3000 763100 |rneed2.so.0.v1.| # CHECK-NEXT: ) # CHECK-NEXT: }