Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -1289,10 +1289,10 @@ // to DT_NEEDED. If that happens, we need to eliminate shared symbols // created from the DSO. Otherwise, they become dangling references // that point to a non-existent DSO. -template static void demoteSharedSymbols() { +static void demoteSharedSymbols() { for (Symbol *Sym : Symtab->getSymbols()) { if (auto *S = dyn_cast(Sym)) { - if (!S->getFile().IsNeeded) { + if (!S->getFile().IsNeeded) { bool Used = S->Used; replaceSymbol(S, nullptr, S->getName(), STB_WEAK, S->StOther, S->Type); @@ -1644,7 +1644,7 @@ // and identical code folding. splitSections(); markLive(); - demoteSharedSymbols(); + demoteSharedSymbols(); mergeSections(); if (Config->ICF != ICFLevel::None) { findKeepUniqueSections(Args); Index: lld/trunk/ELF/InputFiles.h =================================================================== --- lld/trunk/ELF/InputFiles.h +++ lld/trunk/ELF/InputFiles.h @@ -328,19 +328,10 @@ }; // .so file. -template class SharedFile : public ELFFileBase { - using Elf_Dyn = typename ELFT::Dyn; - using Elf_Shdr = typename ELFT::Shdr; - using Elf_Sym = typename ELFT::Sym; - using Elf_Sym_Range = typename ELFT::SymRange; - using Elf_Verdef = typename ELFT::Verdef; - using Elf_Versym = typename ELFT::Versym; - - const Elf_Shdr *VersymSec = nullptr; - const Elf_Shdr *VerdefSec = nullptr; - +class SharedFile : public ELFFileBase { public: - std::vector Verdefs; + // This is actually a vector of Elf_Verdef pointers. + std::vector Verdefs; std::vector DtNeeded; std::string SoName; @@ -348,11 +339,7 @@ SharedFile(MemoryBufferRef M, StringRef DefaultSoName); - void parseDynamic(); - void parseRest(); - uint32_t getAlignment(ArrayRef Sections, const Elf_Sym &Sym); - std::vector parseVerdefs(); - std::vector parseVersyms(); + template void parse(); struct NeededVer { // The string table offset of the version name in the output file. @@ -364,7 +351,7 @@ // Mapping from Elf_Verdef data structures to information about Elf_Vernaux // data structures in the output file. - std::map VerdefMap; + std::map VerdefMap; // Used for --no-allow-shlib-undefined. bool AllNeededIsKnown; @@ -394,7 +381,7 @@ extern std::vector BitcodeFiles; extern std::vector LazyObjFiles; extern std::vector ObjectFiles; -extern std::vector SharedFiles; +extern std::vector SharedFiles; } // namespace elf } // namespace lld Index: lld/trunk/ELF/InputFiles.cpp =================================================================== --- lld/trunk/ELF/InputFiles.cpp +++ lld/trunk/ELF/InputFiles.cpp @@ -43,7 +43,7 @@ std::vector elf::BitcodeFiles; std::vector elf::LazyObjFiles; std::vector elf::ObjectFiles; -std::vector elf::SharedFiles; +std::vector elf::SharedFiles; std::unique_ptr elf::Tar; @@ -869,20 +869,83 @@ return File; } -template -SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) +SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase(SharedKind, M), SoName(DefaultSoName), - IsNeeded(!Config->AsNeeded) { - parseHeader(); + IsNeeded(!Config->AsNeeded) {} + +// Parse the version definitions in the object file if present, and return a +// vector whose nth element contains a pointer to the Elf_Verdef for version +// identifier n. Version identifiers that are not definitions map to nullptr. +template +static std::vector parseVerdefs(const uint8_t *Base, + const typename ELFT::Shdr *Sec) { + if (!Sec) + return {}; + + // We cannot determine the largest verdef identifier without inspecting + // every Elf_Verdef, but both bfd and gold assign verdef identifiers + // sequentially starting from 1, so we predict that the largest identifier + // will be VerdefCount. + unsigned VerdefCount = Sec->sh_info; + std::vector Verdefs(VerdefCount + 1); + + // Build the Verdefs array by following the chain of Elf_Verdef objects + // from the start of the .gnu.version_d section. + const uint8_t *Verdef = Base + Sec->sh_offset; + for (unsigned I = 0; I != VerdefCount; ++I) { + auto *CurVerdef = reinterpret_cast(Verdef); + Verdef += CurVerdef->vd_next; + unsigned VerdefIndex = CurVerdef->vd_ndx; + Verdefs.resize(VerdefIndex + 1); + Verdefs[VerdefIndex] = CurVerdef; + } + return Verdefs; } -// Partially parse the shared object file so that we can call -// getSoName on this object. -template void SharedFile::parseDynamic() { +// We do not usually care about alignments of data in shared object +// files because the loader takes care of it. However, if we promote a +// DSO symbol to point to .bss due to copy relocation, we need to keep +// the original alignment requirements. We infer it in this function. +template +static uint64_t getAlignment(ArrayRef Sections, + const typename ELFT::Sym &Sym) { + uint64_t Ret = UINT64_MAX; + if (Sym.st_value) + Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); + if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) + Ret = std::min(Ret, Sections[Sym.st_shndx].sh_addralign); + return (Ret > UINT32_MAX) ? 0 : Ret; +} + +// Fully parse the shared object file. +// +// This function parses symbol versions. If a DSO has version information, +// the file has a ".gnu.version_d" section which contains symbol version +// definitions. Each symbol is associated to one version through a table in +// ".gnu.version" section. That table is a parallel array for the symbol +// table, and each table entry contains an index in ".gnu.version_d". +// +// The special index 0 is reserved for VERF_NDX_LOCAL and 1 is for +// VER_NDX_GLOBAL. There's no table entry for these special versions in +// ".gnu.version_d". +// +// The file format for symbol versioning is perhaps a bit more complicated +// than necessary, but you can easily understand the code if you wrap your +// head around the data structure described above. +template void SharedFile::parse() { + using Elf_Dyn = typename ELFT::Dyn; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Sym = typename ELFT::Sym; + using Elf_Verdef = typename ELFT::Verdef; + using Elf_Versym = typename ELFT::Versym; + ArrayRef DynamicTags; const ELFFile Obj = this->getObj(); ArrayRef Sections = CHECK(Obj.sections(), this); + const Elf_Shdr *VersymSec = nullptr; + const Elf_Shdr *VerdefSec = nullptr; + // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { @@ -896,16 +959,18 @@ CHECK(Obj.template getSectionContentsAsArray(&Sec), this); break; case SHT_GNU_versym: - this->VersymSec = &Sec; + VersymSec = &Sec; break; case SHT_GNU_verdef: - this->VerdefSec = &Sec; + VerdefSec = &Sec; break; } } - if (this->VersymSec && this->getELFSyms().empty()) + if (VersymSec && this->getELFSyms().empty()) { error("SHT_GNU_versym should be associated with symbol table"); + return; + } // Search for a DT_SONAME tag to initialize this->SoName. for (const Elf_Dyn &Dyn : DynamicTags) { @@ -921,91 +986,38 @@ SoName = this->StringTable.data() + Val; } } -} -// Parses ".gnu.version" section which is a parallel array for the symbol table. -// If a given file doesn't have ".gnu.version" section, returns VER_NDX_GLOBAL. -template std::vector SharedFile::parseVersyms() { - size_t Size = this->getELFSyms().size() - this->FirstGlobal; - if (!VersymSec) - return std::vector(Size, VER_NDX_GLOBAL); + // DSOs are uniquified not by filename but by soname. + DenseMap::iterator It; + bool WasInserted; + std::tie(It, WasInserted) = Symtab->SoNames.try_emplace(SoName, this); + + // If a DSO appears more than once on the command line with and without + // --as-needed, --no-as-needed takes precedence over --as-needed because a + // user can add an extra DSO with --no-as-needed to force it to be added to + // the dependency list. + It->second->IsNeeded |= IsNeeded; + if (!WasInserted) + return; - const char *Base = this->MB.getBuffer().data(); - const Elf_Versym *Versym = - reinterpret_cast(Base + VersymSec->sh_offset) + - this->FirstGlobal; - - std::vector Ret(Size); - for (size_t I = 0; I < Size; ++I) - Ret[I] = Versym[I].vs_index; - return Ret; -} - -// Parse the version definitions in the object file if present. Returns a vector -// whose nth element contains a pointer to the Elf_Verdef for version identifier -// n. Version identifiers that are not definitions map to nullptr. -template -std::vector SharedFile::parseVerdefs() { - if (!VerdefSec) - return {}; + SharedFiles.push_back(this); - // We cannot determine the largest verdef identifier without inspecting - // every Elf_Verdef, but both bfd and gold assign verdef identifiers - // sequentially starting from 1, so we predict that the largest identifier - // will be VerdefCount. - unsigned VerdefCount = VerdefSec->sh_info; - std::vector Verdefs(VerdefCount + 1); + Verdefs = parseVerdefs(Obj.base(), VerdefSec); - // Build the Verdefs array by following the chain of Elf_Verdef objects - // from the start of the .gnu.version_d section. - const char *Base = this->MB.getBuffer().data(); - const char *Verdef = Base + VerdefSec->sh_offset; - for (unsigned I = 0; I != VerdefCount; ++I) { - auto *CurVerdef = reinterpret_cast(Verdef); - Verdef += CurVerdef->vd_next; - unsigned VerdefIndex = CurVerdef->vd_ndx; - Verdefs.resize(VerdefIndex + 1); - Verdefs[VerdefIndex] = CurVerdef; + // Parse ".gnu.version" section which is a parallel array for the symbol + // table. If a given file doesn't have a ".gnu.version" section, we use + // VER_NDX_GLOBAL. + size_t Size = this->getELFSyms().size() - this->FirstGlobal; + std::vector Versyms(Size, VER_NDX_GLOBAL); + if (VersymSec) { + ArrayRef Versym = + CHECK(Obj.template getSectionContentsAsArray(VersymSec), + this) + .slice(FirstGlobal); + for (size_t I = 0; I < Size; ++I) + Versyms[I] = Versym[I].vs_index; } - return Verdefs; -} - -// We do not usually care about alignments of data in shared object -// files because the loader takes care of it. However, if we promote a -// DSO symbol to point to .bss due to copy relocation, we need to keep -// the original alignment requirements. We infer it in this function. -template -uint32_t SharedFile::getAlignment(ArrayRef Sections, - const Elf_Sym &Sym) { - uint64_t Ret = UINT64_MAX; - if (Sym.st_value) - Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); - if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) - Ret = std::min(Ret, Sections[Sym.st_shndx].sh_addralign); - return (Ret > UINT32_MAX) ? 0 : Ret; -} - -// Fully parse the shared object file. This must be called after parseDynamic(). -// -// This function parses symbol versions. If a DSO has version information, -// the file has a ".gnu.version_d" section which contains symbol version -// definitions. Each symbol is associated to one version through a table in -// ".gnu.version" section. That table is a parallel array for the symbol -// table, and each table entry contains an index in ".gnu.version_d". -// -// The special index 0 is reserved for VERF_NDX_LOCAL and 1 is for -// VER_NDX_GLOBAL. There's no table entry for these special versions in -// ".gnu.version_d". -// -// The file format for symbol versioning is perhaps a bit more complicated -// than necessary, but you can easily understand the code if you wrap your -// head around the data structure described above. -template void SharedFile::parseRest() { - Verdefs = parseVerdefs(); // parse .gnu.version_d - std::vector Versyms = parseVersyms(); // parse .gnu.version - ArrayRef Sections = CHECK(this->getObj().sections(), this); - // System libraries can have a lot of symbols with versions. Using a // fixed buffer for computing the versions name (foo@ver) can save a // lot of allocations. @@ -1043,9 +1055,9 @@ Name == "_gp_disp") continue; - uint64_t Alignment = getAlignment(Sections, Sym); + uint64_t Alignment = getAlignment(Sections, Sym); if (!(Versyms[I] & VERSYM_HIDDEN)) - Symtab->addShared(Name, *this, Sym, Alignment, Idx); + Symtab->addShared(Name, *this, Sym, Alignment, Idx); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. @@ -1060,10 +1072,11 @@ } StringRef VerName = - this->StringTable.data() + Verdefs[Idx]->getAux()->vda_name; + this->StringTable.data() + + reinterpret_cast(Verdefs[Idx])->getAux()->vda_name; VersionedNameBuffer.clear(); Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer); - Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx); + Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx); } } @@ -1259,18 +1272,24 @@ } InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { + auto *F = make(MB, DefaultSoName); switch (getELFKind(MB, "")) { case ELF32LEKind: - return make>(MB, DefaultSoName); + F->parseHeader(); + break; case ELF32BEKind: - return make>(MB, DefaultSoName); + F->parseHeader(); + break; case ELF64LEKind: - return make>(MB, DefaultSoName); + F->parseHeader(); + break; case ELF64BEKind: - return make>(MB, DefaultSoName); + F->parseHeader(); + break; default: llvm_unreachable("getELFKind"); } + return F; } MemoryBufferRef LazyObjFile::getBuffer() { @@ -1355,7 +1374,7 @@ template class elf::ObjFile; template class elf::ObjFile; -template class elf::SharedFile; -template class elf::SharedFile; -template class elf::SharedFile; -template class elf::SharedFile; +template void SharedFile::parse(); +template void SharedFile::parse(); +template void SharedFile::parse(); +template void SharedFile::parse(); Index: lld/trunk/ELF/MarkLive.cpp =================================================================== --- lld/trunk/ELF/MarkLive.cpp +++ lld/trunk/ELF/MarkLive.cpp @@ -103,7 +103,7 @@ if (auto *SS = dyn_cast(&Sym)) if (!SS->isWeak()) - SS->getFile().IsNeeded = true; + SS->getFile().IsNeeded = true; for (InputSectionBase *Sec : CNamedSections.lookup(Sym.getName())) enqueue(Sec, 0); @@ -276,7 +276,7 @@ for (Symbol *Sym : Symtab->getSymbols()) if (auto *S = dyn_cast(Sym)) if (S->IsUsedInRegularObj && !S->isWeak()) - S->getFile().IsNeeded = true; + S->getFile().IsNeeded = true; return; } Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -482,7 +482,7 @@ using Elf_Phdr = typename ELFT::Phdr; // Determine if the symbol is read-only by scanning the DSO's program headers. - const SharedFile &File = SS.getFile(); + const SharedFile &File = SS.getFile(); for (const Elf_Phdr &Phdr : check(File.template getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && @@ -501,7 +501,7 @@ static SmallSet getSymbolsAt(SharedSymbol &SS) { using Elf_Sym = typename ELFT::Sym; - SharedFile &File = SS.getFile(); + SharedFile &File = SS.getFile(); SmallSet Ret; for (const Elf_Sym &S : File.template getGlobalELFSyms()) { Index: lld/trunk/ELF/SymbolTable.h =================================================================== --- lld/trunk/ELF/SymbolTable.h +++ lld/trunk/ELF/SymbolTable.h @@ -49,9 +49,8 @@ SectionBase *Section, InputFile *File); template - void addShared(StringRef Name, SharedFile &F, - const typename ELFT::Sym &Sym, uint32_t Alignment, - uint32_t VerdefIndex); + void addShared(StringRef Name, SharedFile &F, const typename ELFT::Sym &Sym, + uint32_t Alignment, uint32_t VerdefIndex); template void addLazyArchive(StringRef Name, ArchiveFile &F, @@ -80,7 +79,7 @@ void handleDynamicList(); // Set of .so files to not link the same shared object file more than once. - llvm::DenseMap SoNames; + llvm::DenseMap SoNames; private: std::pair insertName(StringRef Name); Index: lld/trunk/ELF/SymbolTable.cpp =================================================================== --- lld/trunk/ELF/SymbolTable.cpp +++ lld/trunk/ELF/SymbolTable.cpp @@ -90,25 +90,8 @@ message(toString(File)); // .so file - if (auto *F = dyn_cast>(File)) { - // DSOs are uniquified not by filename but by soname. - F->parseDynamic(); - if (errorCount()) - return; - - // If a DSO appears more than once on the command line with and without - // --as-needed, --no-as-needed takes precedence over --as-needed because a - // user can add an extra DSO with --no-as-needed to force it to be added to - // the dependency list. - DenseMap::iterator It; - bool WasInserted; - std::tie(It, WasInserted) = SoNames.try_emplace(F->SoName, F); - cast>(It->second)->IsNeeded |= F->IsNeeded; - if (!WasInserted) - return; - - SharedFiles.push_back(F); - F->parseRest(); + if (auto *F = dyn_cast(File)) { + F->parse(); return; } @@ -485,7 +468,7 @@ } template -void SymbolTable::addShared(StringRef Name, SharedFile &File, +void SymbolTable::addShared(StringRef Name, SharedFile &File, const typename ELFT::Sym &Sym, uint32_t Alignment, uint32_t VerdefIndex) { // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT @@ -802,15 +785,15 @@ template void SymbolTable::fetchLazy(Symbol *); template void SymbolTable::fetchLazy(Symbol *); -template void SymbolTable::addShared(StringRef, SharedFile &, +template void SymbolTable::addShared(StringRef, SharedFile &, const typename ELF32LE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared(StringRef, SharedFile &, +template void SymbolTable::addShared(StringRef, SharedFile &, const typename ELF32BE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared(StringRef, SharedFile &, +template void SymbolTable::addShared(StringRef, SharedFile &, const typename ELF64LE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared(StringRef, SharedFile &, +template void SymbolTable::addShared(StringRef, SharedFile &, const typename ELF64BE::Sym &, uint32_t Alignment, uint32_t); Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -13,6 +13,7 @@ #ifndef LLD_ELF_SYMBOLS_H #define LLD_ELF_SYMBOLS_H +#include "InputFiles.h" #include "InputSection.h" #include "lld/Common/LLVM.h" #include "lld/Common/Strings.h" @@ -30,8 +31,6 @@ namespace elf { -template class SharedFile; - // This is a StringRef-like container that doesn't run strlen(). // // ELF string tables contain a lot of null-terminated strings. Most of them @@ -266,9 +265,7 @@ this->Type = llvm::ELF::STT_FUNC; } - template SharedFile &getFile() const { - return *cast>(File); - } + SharedFile &getFile() const { return *cast(File); } uint32_t Alignment; Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -809,7 +809,7 @@ // A vector of shared files that need Elf_Verneed data structures and the // string table offsets of their sonames. - std::vector *, size_t>> Needed; + std::vector> Needed; public: void addSymbol(Symbol *Sym) override; Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -1263,11 +1263,9 @@ addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, In.DynStrTab->addString(Config->Rpath)); - for (InputFile *File : SharedFiles) { - SharedFile *F = cast>(File); - if (F->IsNeeded) - addInt(DT_NEEDED, In.DynStrTab->addString(F->SoName)); - } + for (SharedFile *File : SharedFiles) + if (File->IsNeeded) + addInt(DT_NEEDED, In.DynStrTab->addString(File->SoName)); if (!Config->SoName.empty()) addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName)); @@ -2792,7 +2790,7 @@ } template void VersionNeedSection::addSymbol(Symbol *SS) { - auto &File = cast>(*SS->File); + auto &File = cast(*SS->File); if (SS->VerdefIndex == VER_NDX_GLOBAL) { SS->VersionId = VER_NDX_GLOBAL; return; @@ -2803,8 +2801,9 @@ // for the soname. if (File.VerdefMap.empty()) Needed.push_back({&File, In.DynStrTab->addString(File.SoName)}); - const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; - typename SharedFile::NeededVer &NV = File.VerdefMap[Ver]; + auto *Ver = reinterpret_cast( + File.Verdefs[SS->VerdefIndex]); + typename SharedFile::NeededVer &NV = File.VerdefMap[Ver]; // 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 @@ -2822,7 +2821,7 @@ auto *Verneed = reinterpret_cast(Buf); auto *Vernaux = reinterpret_cast(Verneed + Needed.size()); - for (std::pair *, size_t> &P : Needed) { + for (std::pair &P : Needed) { // Create an Elf_Verneed for this DSO. Verneed->vn_version = 1; Verneed->vn_cnt = P.first->VerdefMap.size(); @@ -2839,7 +2838,8 @@ // 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 = NV.first->vd_hash; + Vernaux->vna_hash = + reinterpret_cast(NV.first)->vd_hash; Vernaux->vna_flags = 0; Vernaux->vna_other = NV.second.Index; Vernaux->vna_name = NV.second.StrTab; @@ -2860,7 +2860,7 @@ template size_t VersionNeedSection::getSize() const { unsigned Size = Needed.size() * sizeof(Elf_Verneed); - for (const std::pair *, size_t> &P : Needed) + for (const std::pair &P : Needed) Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux); return Size; } Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -1628,15 +1628,14 @@ // ld.bfd traces all DT_NEEDED to emulate the logic of the dynamic linker to // catch more cases. That is too much for us. Our approach resembles the one // used in ld.gold, achieves a good balance to be useful but not too smart. - for (InputFile *File : SharedFiles) { - SharedFile *F = cast>(File); - F->AllNeededIsKnown = llvm::all_of(F->DtNeeded, [&](StringRef Needed) { - return Symtab->SoNames.count(Needed); - }); - } + for (SharedFile *File : SharedFiles) + File->AllNeededIsKnown = + llvm::all_of(File->DtNeeded, [&](StringRef Needed) { + return Symtab->SoNames.count(Needed); + }); for (Symbol *Sym : Symtab->getSymbols()) if (Sym->isUndefined() && !Sym->isWeak()) - if (auto *F = dyn_cast_or_null>(Sym->File)) + if (auto *F = dyn_cast_or_null(Sym->File)) if (F->AllNeededIsKnown) error(toString(F) + ": undefined reference to " + toString(*Sym)); } @@ -1651,7 +1650,7 @@ if (Sym->includeInDynsym()) { In.DynSymTab->addSymbol(Sym); - if (auto *File = dyn_cast_or_null>(Sym->File)) + if (auto *File = dyn_cast_or_null(Sym->File)) if (File->IsNeeded && !Sym->isUndefined()) In.VerNeed->addSymbol(Sym); }