1c94d393aSSam Clegg //===- SymbolTable.cpp ----------------------------------------------------===// 2c94d393aSSam Clegg // 3c94d393aSSam Clegg // The LLVM Linker 4c94d393aSSam Clegg // 5c94d393aSSam Clegg // This file is distributed under the University of Illinois Open Source 6c94d393aSSam Clegg // License. See LICENSE.TXT for details. 7c94d393aSSam Clegg // 8c94d393aSSam Clegg //===----------------------------------------------------------------------===// 9c94d393aSSam Clegg 10c94d393aSSam Clegg #include "SymbolTable.h" 11c94d393aSSam Clegg 12c94d393aSSam Clegg #include "Config.h" 13c94d393aSSam Clegg #include "Strings.h" 14c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h" 15*2017d52bSRui Ueyama #include "lld/Common/Memory.h" 16c94d393aSSam Clegg 17c94d393aSSam Clegg #include <unordered_set> 18c94d393aSSam Clegg 19c94d393aSSam Clegg #define DEBUG_TYPE "lld" 20c94d393aSSam Clegg 21c94d393aSSam Clegg using namespace llvm; 22c94d393aSSam Clegg using namespace lld; 23c94d393aSSam Clegg using namespace lld::wasm; 24c94d393aSSam Clegg 25c94d393aSSam Clegg SymbolTable *lld::wasm::Symtab; 26c94d393aSSam Clegg 27c94d393aSSam Clegg void SymbolTable::addFile(InputFile *File) { 28c94d393aSSam Clegg log("Processing: " + toString(File)); 29c94d393aSSam Clegg File->parse(); 30c94d393aSSam Clegg 31c94d393aSSam Clegg if (auto *F = dyn_cast<ObjFile>(File)) 32c94d393aSSam Clegg ObjectFiles.push_back(F); 33c94d393aSSam Clegg } 34c94d393aSSam Clegg 35c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() { 36c94d393aSSam Clegg std::unordered_set<Symbol *> Undefs; 37a80d94d5SSam Clegg for (auto &I : SymMap) { 38c94d393aSSam Clegg Symbol *Sym = I.second; 39c94d393aSSam Clegg if (Sym->isUndefined() && !Sym->isWeak() && 40c94d393aSSam Clegg Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) { 41c94d393aSSam Clegg Undefs.insert(Sym); 42c94d393aSSam Clegg } 43c94d393aSSam Clegg } 44c94d393aSSam Clegg 45c94d393aSSam Clegg if (Undefs.empty()) 46c94d393aSSam Clegg return; 47c94d393aSSam Clegg 48c94d393aSSam Clegg for (ObjFile *File : ObjectFiles) 49c94d393aSSam Clegg for (Symbol *Sym : File->getSymbols()) 50c94d393aSSam Clegg if (Undefs.count(Sym)) 51c94d393aSSam Clegg error(toString(File) + ": undefined symbol: " + toString(*Sym)); 52c94d393aSSam Clegg 53c94d393aSSam Clegg for (Symbol *Sym : Undefs) 54c94d393aSSam Clegg if (!Sym->getFile()) 55c94d393aSSam Clegg error("undefined symbol: " + toString(*Sym)); 56c94d393aSSam Clegg } 57c94d393aSSam Clegg 58c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) { 59a80d94d5SSam Clegg auto It = SymMap.find(CachedHashStringRef(Name)); 60a80d94d5SSam Clegg if (It == SymMap.end()) 61c94d393aSSam Clegg return nullptr; 62c94d393aSSam Clegg return It->second; 63c94d393aSSam Clegg } 64c94d393aSSam Clegg 65c94d393aSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { 66a80d94d5SSam Clegg Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; 67c94d393aSSam Clegg if (Sym) 68c94d393aSSam Clegg return {Sym, false}; 69c94d393aSSam Clegg Sym = make<Symbol>(Name, false); 70c94d393aSSam Clegg return {Sym, true}; 71c94d393aSSam Clegg } 72c94d393aSSam Clegg 73c94d393aSSam Clegg void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { 74c94d393aSSam Clegg error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + 75c94d393aSSam Clegg toString(Existing->getFile()) + "\n>>> defined in " + 76e2ed092eSSam Clegg toString(NewFile)); 77c94d393aSSam Clegg } 78c94d393aSSam Clegg 79c94d393aSSam Clegg static void checkSymbolTypes(Symbol *Existing, InputFile *F, 80c94d393aSSam Clegg const WasmSymbol *New) { 81c94d393aSSam Clegg if (Existing->isLazy()) 82c94d393aSSam Clegg return; 83c94d393aSSam Clegg 84c94d393aSSam Clegg bool NewIsFunction = New->Type == WasmSymbol::SymbolType::FUNCTION_EXPORT || 85c94d393aSSam Clegg New->Type == WasmSymbol::SymbolType::FUNCTION_IMPORT; 86c94d393aSSam Clegg if (Existing->isFunction() == NewIsFunction) 87c94d393aSSam Clegg return; 88c94d393aSSam Clegg 89c94d393aSSam Clegg error("symbol type mismatch: " + New->Name + "\n>>> defined as " + 90e2ed092eSSam Clegg (Existing->isFunction() ? "Function" : "Global") + " in " + 91e2ed092eSSam Clegg toString(Existing->getFile()) + "\n>>> defined as " + 92e2ed092eSSam Clegg (NewIsFunction ? "Function" : "Global") + " in " + F->getName()); 93c94d393aSSam Clegg } 94c94d393aSSam Clegg 95c94d393aSSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name) { 96c94d393aSSam Clegg DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n"); 97c94d393aSSam Clegg Symbol *S; 98c94d393aSSam Clegg bool WasInserted; 99c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 100c94d393aSSam Clegg if (WasInserted) 101c94d393aSSam Clegg S->update(Symbol::DefinedGlobalKind); 102c94d393aSSam Clegg else if (!S->isGlobal()) 103c94d393aSSam Clegg error("symbol type mismatch: " + Name); 104c94d393aSSam Clegg return S; 105c94d393aSSam Clegg } 106c94d393aSSam Clegg 107c94d393aSSam Clegg Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym, 108c94d393aSSam Clegg const InputSegment *Segment) { 109c94d393aSSam Clegg DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n"); 110c94d393aSSam Clegg Symbol *S; 111c94d393aSSam Clegg bool WasInserted; 112c94d393aSSam Clegg Symbol::Kind Kind = Symbol::DefinedFunctionKind; 113c94d393aSSam Clegg if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT) 114c94d393aSSam Clegg Kind = Symbol::DefinedGlobalKind; 115c94d393aSSam Clegg 116c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Sym->Name); 117c94d393aSSam Clegg if (WasInserted) { 118c94d393aSSam Clegg S->update(Kind, F, Sym, Segment); 119c94d393aSSam Clegg } else if (!S->isDefined()) { 120c94d393aSSam Clegg // The existing symbol table entry is undefined. The new symbol replaces 121c94d393aSSam Clegg // it 122c94d393aSSam Clegg DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name 123c94d393aSSam Clegg << "\n"); 124c94d393aSSam Clegg checkSymbolTypes(S, F, Sym); 125c94d393aSSam Clegg S->update(Kind, F, Sym, Segment); 126c94d393aSSam Clegg } else if (Sym->isWeak()) { 127c94d393aSSam Clegg // the new symbol is weak we can ignore it 128c94d393aSSam Clegg DEBUG(dbgs() << "existing symbol takes precensence\n"); 129c94d393aSSam Clegg } else if (S->isWeak()) { 130c94d393aSSam Clegg // the new symbol is not weak and the existing symbol is, so we replace 131c94d393aSSam Clegg // it 132c94d393aSSam Clegg DEBUG(dbgs() << "replacing existing weak symbol\n"); 133c94d393aSSam Clegg S->update(Kind, F, Sym, Segment); 134c94d393aSSam Clegg } else { 135c94d393aSSam Clegg // niether symbol is week. They conflict. 136c94d393aSSam Clegg reportDuplicate(S, F); 137c94d393aSSam Clegg } 138c94d393aSSam Clegg return S; 139c94d393aSSam Clegg } 140c94d393aSSam Clegg 141c94d393aSSam Clegg Symbol *SymbolTable::addUndefinedFunction(StringRef Name) { 142c94d393aSSam Clegg Symbol *S; 143c94d393aSSam Clegg bool WasInserted; 144c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 145c94d393aSSam Clegg if (WasInserted) 146c94d393aSSam Clegg S->update(Symbol::UndefinedFunctionKind); 147c94d393aSSam Clegg else if (!S->isFunction()) 148c94d393aSSam Clegg error("symbol type mismatch: " + Name); 149c94d393aSSam Clegg return S; 150c94d393aSSam Clegg } 151c94d393aSSam Clegg 152c94d393aSSam Clegg Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym) { 153c94d393aSSam Clegg DEBUG(dbgs() << "addUndefined: " << displayName(Sym->Name) << "\n"); 154c94d393aSSam Clegg Symbol *S; 155c94d393aSSam Clegg bool WasInserted; 156c94d393aSSam Clegg Symbol::Kind Kind = Symbol::UndefinedFunctionKind; 157c94d393aSSam Clegg if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT) 158c94d393aSSam Clegg Kind = Symbol::UndefinedGlobalKind; 159c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Sym->Name); 160c94d393aSSam Clegg if (WasInserted) { 161c94d393aSSam Clegg S->update(Kind, F, Sym); 162c94d393aSSam Clegg } else if (S->isLazy()) { 163c94d393aSSam Clegg DEBUG(dbgs() << "resolved by existing lazy\n"); 164c94d393aSSam Clegg auto *AF = cast<ArchiveFile>(S->getFile()); 165c94d393aSSam Clegg AF->addMember(&S->getArchiveSymbol()); 166c94d393aSSam Clegg } else if (S->isDefined()) { 167c94d393aSSam Clegg DEBUG(dbgs() << "resolved by existing\n"); 168c94d393aSSam Clegg checkSymbolTypes(S, F, Sym); 169c94d393aSSam Clegg } 170c94d393aSSam Clegg return S; 171c94d393aSSam Clegg } 172c94d393aSSam Clegg 173c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) { 174c94d393aSSam Clegg DEBUG(dbgs() << "addLazy: " << displayName(Sym->getName()) << "\n"); 175c94d393aSSam Clegg StringRef Name = Sym->getName(); 176c94d393aSSam Clegg Symbol *S; 177c94d393aSSam Clegg bool WasInserted; 178c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 179c94d393aSSam Clegg if (WasInserted) { 180c94d393aSSam Clegg S->update(Symbol::LazyKind, F); 181c94d393aSSam Clegg S->setArchiveSymbol(*Sym); 182c94d393aSSam Clegg } else if (S->isUndefined()) { 183c94d393aSSam Clegg // There is an existing undefined symbol. The can load from the 184c94d393aSSam Clegg // archive. 185c94d393aSSam Clegg DEBUG(dbgs() << "replacing existing undefined\n"); 186c94d393aSSam Clegg F->addMember(Sym); 187c94d393aSSam Clegg } 188c94d393aSSam Clegg } 189