//===- SymbolTable.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "SymbolTable.h" #include "Config.h" #include "Error.h" #include "Symbols.h" using namespace llvm; using namespace llvm::object; using namespace lld; using namespace lld::elf2; SymbolTable::SymbolTable() {} void SymbolTable::addFile(std::unique_ptr File) { File->parse(); InputFile *FileP = File.release(); if (auto *AF = dyn_cast(FileP)) { ArchiveFiles.emplace_back(AF); for (Lazy &Sym : AF->getLazySymbols()) addLazy(&Sym); return; } addELFFile(cast(FileP)); } template void SymbolTable::init() { if (Config->Shared) return; EntrySym = new (Alloc) Undefined("_start", Undefined::Synthetic); resolve(EntrySym); } template void SymbolTable::addELFFile(ELFFileBase *File) { if (const ELFFileBase *Old = getFirstELF()) { if (!Old->isCompatibleWith(*File)) error(Twine(Old->getName() + " is incompatible with " + File->getName())); } else { init(); } if (auto *O = dyn_cast(File)) { ObjectFiles.emplace_back(O); for (SymbolBody *Body : O->getSymbols()) resolve(Body); } if (auto *S = dyn_cast>(File)) { SharedFiles.emplace_back(S); for (SharedSymbol &Body : S->getSharedSymbols()) resolve(&Body); } } void SymbolTable::addELFFile(ELFFileBase *File) { switch (File->getELFKind()) { case ELF32LEKind: addELFFile(File); break; case ELF32BEKind: addELFFile(File); break; case ELF64LEKind: addELFFile(File); break; case ELF64BEKind: addELFFile(File); break; } } // This function resolves conflicts if there's an existing symbol with // the same name. Decisions are made based on symbol type. template void SymbolTable::resolve(SymbolBody *New) { Symbol *Sym = insert(New); if (Sym->Body == New) return; SymbolBody *Existing = Sym->Body; if (Lazy *L = dyn_cast(Existing)) { if (New->isUndefined()) { addMemberFile(L); return; } // Found a definition for something also in an archive. Ignore the archive // definition. Sym->Body = New; return; } // compare() returns -1, 0, or 1 if the lhs symbol is less preferable, // equivalent (conflicting), or more preferable, respectively. int comp = Existing->compare(New); if (comp < 0) Sym->Body = New; if (comp == 0) error(Twine("duplicate symbol: ") + Sym->Body->getName()); } Symbol *SymbolTable::insert(SymbolBody *New) { // Find an existing Symbol or create and insert a new one. StringRef Name = New->getName(); Symbol *&Sym = Symtab[Name]; if (!Sym) { Sym = new (Alloc) Symbol(New); New->setBackref(Sym); return Sym; } New->setBackref(Sym); return Sym; } void SymbolTable::addLazy(Lazy *New) { Symbol *Sym = insert(New); if (Sym->Body == New) return; SymbolBody *Existing = Sym->Body; if (Existing->isDefined() || Existing->isLazy()) return; Sym->Body = New; assert(Existing->isUndefined() && "Unexpected symbol kind."); addMemberFile(New); } void SymbolTable::addMemberFile(Lazy *Body) { std::unique_ptr File = Body->getMember(); // getMember returns nullptr if the member was already read from the library. if (!File) return; addFile(std::move(File)); }