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