//===- SymbolTable.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Config.h" #include "Driver.h" #include "Error.h" #include "SymbolTable.h" #include "llvm/ADT/STLExtras.h" #include "llvm/LTO/LTOCodeGenerator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; namespace lld { namespace coff { SymbolTable::SymbolTable() { resolve(new (Alloc) DefinedAbsolute("__ImageBase", Config->ImageBase)); if (!Config->EntryName.empty()) resolve(new (Alloc) Undefined(Config->EntryName)); } std::error_code SymbolTable::addFile(std::unique_ptr File) { if (auto EC = File->parse()) return EC; InputFile *FileP = File.release(); if (auto *P = dyn_cast(FileP)) return addObject(P); if (auto *P = dyn_cast(FileP)) return addArchive(P); if (auto *P = dyn_cast(FileP)) return addBitcode(P); return addImport(cast(FileP)); } std::error_code SymbolTable::addDirectives(InputFile *File) { StringRef S = File->getDirectives(); if (S.empty()) return std::error_code(); std::vector> Libs; if (auto EC = Driver->parseDirectives(S, &Libs)) return EC; for (std::unique_ptr &Lib : Libs) { if (Config->Verbose) { llvm::outs() << "Reading " << Lib->getName() << " for " << File->getName() << "\n"; } addFile(std::move(Lib)); } return std::error_code(); } std::error_code SymbolTable::addObject(ObjectFile *File) { ObjectFiles.emplace_back(File); for (SymbolBody *Body : File->getSymbols()) if (Body->isExternal()) if (auto EC = resolve(Body)) return EC; // If an object file contains .drectve section, read it and add // files listed in the section. return addDirectives(File); } std::error_code SymbolTable::addArchive(ArchiveFile *File) { ArchiveFiles.emplace_back(File); for (SymbolBody *Body : File->getSymbols()) if (auto EC = resolve(Body)) return EC; return std::error_code(); } std::error_code SymbolTable::addBitcode(BitcodeFile *File) { BitcodeFiles.emplace_back(File); for (SymbolBody *Body : File->getSymbols()) if (Body->isExternal()) if (auto EC = resolve(Body)) return EC; // Add any linker directives from the module flags metadata. return addDirectives(File); } std::error_code SymbolTable::addImport(ImportFile *File) { ImportFiles.emplace_back(File); for (SymbolBody *Body : File->getSymbols()) if (auto EC = resolve(Body)) return EC; return std::error_code(); } bool SymbolTable::reportRemainingUndefines() { bool Ret = false; for (auto &I : Symtab) { Symbol *Sym = I.second; auto *Undef = dyn_cast(Sym->Body); if (!Undef) continue; if (SymbolBody *Alias = Undef->getWeakAlias()) { Sym->Body = Alias->getReplacement(); if (!isa(Sym->Body)) { // Aliases are yet another symbols pointed by other symbols // that could also remain undefined. llvm::errs() << "undefined symbol: " << Undef->getName() << "\n"; Ret = true; } continue; } llvm::errs() << "undefined symbol: " << Undef->getName() << "\n"; Ret = true; } return Ret; } // This function resolves conflicts if there's an existing symbol with // the same name. Decisions are made based on symbol type. std::error_code SymbolTable::resolve(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 std::error_code(); } New->setBackref(Sym); // compare() returns -1, 0, or 1 if the lhs symbol is less preferable, // equivalent (conflicting), or more preferable, respectively. SymbolBody *Existing = Sym->Body; int comp = Existing->compare(New); if (comp < 0) Sym->Body = New; if (comp == 0) { llvm::errs() << "duplicate symbol: " << Name << "\n"; return make_error_code(LLDError::DuplicateSymbols); } // If we have an Undefined symbol for a Lazy symbol, we need // to read an archive member to replace the Lazy symbol with // a Defined symbol. if (isa(Existing) || isa(New)) if (auto *B = dyn_cast(Sym->Body)) return addMemberFile(B); return std::error_code(); } // Reads an archive member file pointed by a given symbol. std::error_code SymbolTable::addMemberFile(Lazy *Body) { auto FileOrErr = Body->getMember(); if (auto EC = FileOrErr.getError()) return EC; std::unique_ptr File = std::move(FileOrErr.get()); // getMember returns an empty buffer if the member was already // read from the library. if (!File) return std::error_code(); if (Config->Verbose) llvm::outs() << "Loaded " << File->getShortName() << " for " << Body->getName() << "\n"; return addFile(std::move(File)); } std::vector SymbolTable::getChunks() { std::vector Res; for (std::unique_ptr &File : ObjectFiles) { std::vector &V = File->getChunks(); Res.insert(Res.end(), V.begin(), V.end()); } return Res; } Defined *SymbolTable::find(StringRef Name) { auto It = Symtab.find(Name); if (It == Symtab.end()) return nullptr; if (auto *Def = dyn_cast(It->second->Body)) return Def; return nullptr; } // Windows specific -- Link default entry point name. ErrorOr SymbolTable::findDefaultEntry() { // User-defined main functions and their corresponding entry points. static const char *Entries[][2] = { {"main", "mainCRTStartup"}, {"wmain", "wmainCRTStartup"}, {"WinMain", "WinMainCRTStartup"}, {"wWinMain", "wWinMainCRTStartup"}, }; for (auto E : Entries) { if (find(E[1])) return StringRef(E[1]); if (!find(E[0])) continue; if (auto EC = resolve(new (Alloc) Undefined(E[1]))) return EC; return StringRef(E[1]); } llvm::errs() << "entry point must be defined\n"; return make_error_code(LLDError::InvalidOption); } std::error_code SymbolTable::addUndefined(StringRef Name) { return resolve(new (Alloc) Undefined(Name)); } // Resolve To, and make From an alias to To. std::error_code SymbolTable::rename(StringRef From, StringRef To) { SymbolBody *Body = new (Alloc) Undefined(To); if (auto EC = resolve(Body)) return EC; Symtab[From]->Body = Body->getReplacement(); return std::error_code(); } void SymbolTable::dump() { for (auto &P : Symtab) { Symbol *Ref = P.second; if (auto *Body = dyn_cast(Ref->Body)) llvm::dbgs() << Twine::utohexstr(Config->ImageBase + Body->getRVA()) << " " << Body->getName() << "\n"; } } std::error_code SymbolTable::addCombinedLTOObject() { if (BitcodeFiles.empty()) return std::error_code(); // Create an object file and add it to the symbol table by replacing any // DefinedBitcode symbols with the definitions in the object file. LTOCodeGenerator CG; auto FileOrErr = createLTOObject(&CG); if (auto EC = FileOrErr.getError()) return EC; ObjectFile *Obj = FileOrErr.get(); for (SymbolBody *Body : Obj->getSymbols()) { if (!Body->isExternal()) continue; // Find an existing Symbol. We should not see any new undefined symbols at // this point. StringRef Name = Body->getName(); Symbol *&Sym = Symtab[Name]; if (!Sym) { if (!isa(Body)) { llvm::errs() << "LTO: undefined symbol: " << Name << '\n'; return make_error_code(LLDError::BrokenFile); } Sym = new (Alloc) Symbol(Body); Body->setBackref(Sym); continue; } Body->setBackref(Sym); if (isa(Sym->Body)) { // The symbol should now be defined. if (!isa(Body)) { llvm::errs() << "LTO: undefined symbol: " << Name << '\n'; return make_error_code(LLDError::BrokenFile); } Sym->Body = Body; } else { int comp = Sym->Body->compare(Body); if (comp < 0) Sym->Body = Body; if (comp == 0) { llvm::errs() << "LTO: unexpected duplicate symbol: " << Name << "\n"; return make_error_code(LLDError::BrokenFile); } } // We may see new references to runtime library symbols such as __chkstk // here. These symbols must be wholly defined in non-bitcode files. if (auto *B = dyn_cast(Sym->Body)) { size_t NumBitcodeFiles = BitcodeFiles.size(); if (auto EC = addMemberFile(B)) return EC; if (BitcodeFiles.size() != NumBitcodeFiles) { llvm::errs() << "LTO: late loaded symbol created new bitcode reference: " << Name << "\n"; return make_error_code(LLDError::BrokenFile); } } } // New runtime library symbol references may have created undefined references. if (reportRemainingUndefines()) return make_error_code(LLDError::BrokenFile); return std::error_code(); } // Combine and compile bitcode files and then return the result // as a regular COFF object file. ErrorOr SymbolTable::createLTOObject(LTOCodeGenerator *CG) { // All symbols referenced by non-bitcode objects must be preserved. for (std::unique_ptr &File : ObjectFiles) for (SymbolBody *Body : File->getSymbols()) if (auto *S = dyn_cast(Body->getReplacement())) CG->addMustPreserveSymbol(S->getName()); // Likewise for bitcode symbols which we initially resolved to non-bitcode. for (std::unique_ptr &File : BitcodeFiles) for (SymbolBody *Body : File->getSymbols()) if (isa(Body) && !isa(Body->getReplacement())) CG->addMustPreserveSymbol(Body->getName()); // Likewise for other symbols that must be preserved. for (StringRef Name : Config->GCRoots) if (isa(Symtab[Name]->Body)) CG->addMustPreserveSymbol(Name); CG->setModule(BitcodeFiles[0]->releaseModule()); for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I) CG->addModule(BitcodeFiles[I]->getModule()); std::string ErrMsg; LTOMB = CG->compile(false, false, false, ErrMsg); // take MB ownership if (!LTOMB) { llvm::errs() << ErrMsg << '\n'; return make_error_code(LLDError::BrokenFile); } auto Obj = new ObjectFile(LTOMB->getMemBufferRef()); ObjectFiles.emplace_back(Obj); if (auto EC = Obj->parse()) return EC; return Obj; } } // namespace coff } // namespace lld