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" 13b8621596SSam Clegg #include "WriterUtils.h" 14c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h" 152017d52bSRui 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; 3774fe0ba1SSam Clegg for (Symbol *Sym : SymVector) { 38c94d393aSSam Clegg if (Sym->isUndefined() && !Sym->isWeak() && 39c94d393aSSam Clegg Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) { 40c94d393aSSam Clegg Undefs.insert(Sym); 41c94d393aSSam Clegg } 42c94d393aSSam Clegg } 43c94d393aSSam Clegg 44c94d393aSSam Clegg if (Undefs.empty()) 45c94d393aSSam Clegg return; 46c94d393aSSam Clegg 47c94d393aSSam Clegg for (ObjFile *File : ObjectFiles) 48c94d393aSSam Clegg for (Symbol *Sym : File->getSymbols()) 49c94d393aSSam Clegg if (Undefs.count(Sym)) 50c94d393aSSam Clegg error(toString(File) + ": undefined symbol: " + toString(*Sym)); 51c94d393aSSam Clegg 52c94d393aSSam Clegg for (Symbol *Sym : Undefs) 53c94d393aSSam Clegg if (!Sym->getFile()) 54c94d393aSSam Clegg error("undefined symbol: " + toString(*Sym)); 55c94d393aSSam Clegg } 56c94d393aSSam Clegg 57c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) { 58a80d94d5SSam Clegg auto It = SymMap.find(CachedHashStringRef(Name)); 59a80d94d5SSam Clegg if (It == SymMap.end()) 60c94d393aSSam Clegg return nullptr; 61c94d393aSSam Clegg return It->second; 62c94d393aSSam Clegg } 63c94d393aSSam Clegg 64c94d393aSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { 65a80d94d5SSam Clegg Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; 66c94d393aSSam Clegg if (Sym) 67c94d393aSSam Clegg return {Sym, false}; 68c94d393aSSam Clegg Sym = make<Symbol>(Name, false); 6974fe0ba1SSam Clegg SymVector.emplace_back(Sym); 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 79b8621596SSam Clegg // Get the signature for a given function symbol, either by looking 80b8621596SSam Clegg // it up in function sections (for defined functions), of the imports section 81b8621596SSam Clegg // (for imported functions). 82b8621596SSam Clegg static const WasmSignature *getFunctionSig(const ObjFile &Obj, 83b8621596SSam Clegg const WasmSymbol &Sym) { 84b8621596SSam Clegg DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n"); 85b8621596SSam Clegg const WasmObjectFile *WasmObj = Obj.getWasmObj(); 86b8621596SSam Clegg uint32_t FunctionType; 87b8621596SSam Clegg if (Obj.isImportedFunction(Sym.ElementIndex)) { 88b8621596SSam Clegg const WasmImport &Import = WasmObj->imports()[Sym.ImportIndex]; 89b8621596SSam Clegg FunctionType = Import.SigIndex; 90b8621596SSam Clegg } else { 91b8621596SSam Clegg uint32_t FuntionIndex = Sym.ElementIndex - Obj.NumFunctionImports(); 92b8621596SSam Clegg FunctionType = WasmObj->functionTypes()[FuntionIndex]; 93b8621596SSam Clegg } 94b8621596SSam Clegg return &WasmObj->types()[FunctionType]; 95b8621596SSam Clegg } 96b8621596SSam Clegg 97b8621596SSam Clegg // Check the type of new symbol matches that of the symbol is replacing. 98b8621596SSam Clegg // For functions this can also involve verifying that the signatures match. 99b8621596SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, 100b8621596SSam Clegg const WasmSymbol &New, 101b8621596SSam Clegg const WasmSignature *NewSig) { 102b8621596SSam Clegg if (Existing.isLazy()) 103c94d393aSSam Clegg return; 104c94d393aSSam Clegg 105b8621596SSam Clegg bool NewIsFunction = New.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT || 106b8621596SSam Clegg New.Type == WasmSymbol::SymbolType::FUNCTION_IMPORT; 107b8621596SSam Clegg 108b8621596SSam Clegg // First check the symbol types match (i.e. either both are function 109b8621596SSam Clegg // symbols or both are data symbols). 110b8621596SSam Clegg if (Existing.isFunction() != NewIsFunction) { 111b8621596SSam Clegg error("symbol type mismatch: " + New.Name + "\n>>> defined as " + 112b8621596SSam Clegg (Existing.isFunction() ? "Function" : "Global") + " in " + 113b8621596SSam Clegg toString(Existing.getFile()) + "\n>>> defined as " + 114b8621596SSam Clegg (NewIsFunction ? "Function" : "Global") + " in " + F.getName()); 115b8621596SSam Clegg return; 116b8621596SSam Clegg } 117b8621596SSam Clegg 118b8621596SSam Clegg // For function symbols, optionally check the function signature matches too. 119b8621596SSam Clegg if (!NewIsFunction || !Config->CheckSignatures) 120c94d393aSSam Clegg return; 121*31de2f0cSSam Clegg // Skip the signature check if the existing function has no signature (e.g. 122*31de2f0cSSam Clegg // if it is an undefined symbol generated by --undefined command line flag). 123*31de2f0cSSam Clegg if (!Existing.hasFunctionType()) 124*31de2f0cSSam Clegg return; 125c94d393aSSam Clegg 126b8621596SSam Clegg DEBUG(dbgs() << "checkSymbolTypes: " << New.Name << "\n"); 127b8621596SSam Clegg assert(NewSig); 128b8621596SSam Clegg 129b8621596SSam Clegg const WasmSignature &OldSig = Existing.getFunctionType(); 130b8621596SSam Clegg if (*NewSig == OldSig) 131b8621596SSam Clegg return; 132b8621596SSam Clegg 133b8621596SSam Clegg error("function signature mismatch: " + New.Name + "\n>>> defined as " + 134b8621596SSam Clegg toString(OldSig) + " in " + toString(Existing.getFile()) + 135b8621596SSam Clegg "\n>>> defined as " + toString(*NewSig) + " in " + F.getName()); 136c94d393aSSam Clegg } 137c94d393aSSam Clegg 138c94d393aSSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name) { 139c94d393aSSam Clegg DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n"); 140c94d393aSSam Clegg Symbol *S; 141c94d393aSSam Clegg bool WasInserted; 142c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 143c94d393aSSam Clegg if (WasInserted) 144c94d393aSSam Clegg S->update(Symbol::DefinedGlobalKind); 145c94d393aSSam Clegg else if (!S->isGlobal()) 146c94d393aSSam Clegg error("symbol type mismatch: " + Name); 147c94d393aSSam Clegg return S; 148c94d393aSSam Clegg } 149c94d393aSSam Clegg 150c94d393aSSam Clegg Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym, 151c94d393aSSam Clegg const InputSegment *Segment) { 152c94d393aSSam Clegg DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n"); 153c94d393aSSam Clegg Symbol *S; 154c94d393aSSam Clegg bool WasInserted; 155c94d393aSSam Clegg Symbol::Kind Kind = Symbol::DefinedFunctionKind; 156b8621596SSam Clegg const WasmSignature *NewSig = nullptr; 157c94d393aSSam Clegg if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT) 158c94d393aSSam Clegg Kind = Symbol::DefinedGlobalKind; 159b8621596SSam Clegg else 160b8621596SSam Clegg NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym); 161c94d393aSSam Clegg 162c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Sym->Name); 163c94d393aSSam Clegg if (WasInserted) { 164b8621596SSam Clegg S->update(Kind, F, Sym, Segment, NewSig); 165b8621596SSam Clegg } else if (S->isLazy()) { 166b8621596SSam Clegg // The existing symbol is lazy. Replace it without checking types since 167b8621596SSam Clegg // lazy symbols don't have any type information. 168b8621596SSam Clegg DEBUG(dbgs() << "replacing existing lazy symbol: " << Sym->Name << "\n"); 169b8621596SSam Clegg S->update(Kind, F, Sym, Segment, NewSig); 170c94d393aSSam Clegg } else if (!S->isDefined()) { 171c94d393aSSam Clegg // The existing symbol table entry is undefined. The new symbol replaces 17249ed9262SSam Clegg // it, after checking the type matches 173c94d393aSSam Clegg DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name 174c94d393aSSam Clegg << "\n"); 175b8621596SSam Clegg checkSymbolTypes(*S, *F, *Sym, NewSig); 176b8621596SSam Clegg S->update(Kind, F, Sym, Segment, NewSig); 177c94d393aSSam Clegg } else if (Sym->isWeak()) { 178c94d393aSSam Clegg // the new symbol is weak we can ignore it 17949ed9262SSam Clegg DEBUG(dbgs() << "existing symbol takes precedence\n"); 180c94d393aSSam Clegg } else if (S->isWeak()) { 181c94d393aSSam Clegg // the new symbol is not weak and the existing symbol is, so we replace 182c94d393aSSam Clegg // it 183c94d393aSSam Clegg DEBUG(dbgs() << "replacing existing weak symbol\n"); 184b8621596SSam Clegg checkSymbolTypes(*S, *F, *Sym, NewSig); 185b8621596SSam Clegg S->update(Kind, F, Sym, Segment, NewSig); 186c94d393aSSam Clegg } else { 18749ed9262SSam Clegg // neither symbol is week. They conflict. 188c94d393aSSam Clegg reportDuplicate(S, F); 189c94d393aSSam Clegg } 190c94d393aSSam Clegg return S; 191c94d393aSSam Clegg } 192c94d393aSSam Clegg 193b8621596SSam Clegg Symbol *SymbolTable::addUndefinedFunction(StringRef Name, 194b8621596SSam Clegg const WasmSignature *Type) { 195c94d393aSSam Clegg Symbol *S; 196c94d393aSSam Clegg bool WasInserted; 197c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 198b8621596SSam Clegg if (WasInserted) { 199b8621596SSam Clegg S->update(Symbol::UndefinedFunctionKind, nullptr, nullptr, nullptr, Type); 200b8621596SSam Clegg } else if (!S->isFunction()) { 201c94d393aSSam Clegg error("symbol type mismatch: " + Name); 202b8621596SSam Clegg } 203c94d393aSSam Clegg return S; 204c94d393aSSam Clegg } 205c94d393aSSam Clegg 206c94d393aSSam Clegg Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym) { 207a681a116SSam Clegg DEBUG(dbgs() << "addUndefined: " << Sym->Name << "\n"); 208c94d393aSSam Clegg Symbol *S; 209c94d393aSSam Clegg bool WasInserted; 210c94d393aSSam Clegg Symbol::Kind Kind = Symbol::UndefinedFunctionKind; 211b8621596SSam Clegg const WasmSignature *NewSig = nullptr; 212c94d393aSSam Clegg if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT) 213c94d393aSSam Clegg Kind = Symbol::UndefinedGlobalKind; 214b8621596SSam Clegg else 215b8621596SSam Clegg NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym); 216c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Sym->Name); 217c94d393aSSam Clegg if (WasInserted) { 218b8621596SSam Clegg S->update(Kind, F, Sym, nullptr, NewSig); 219c94d393aSSam Clegg } else if (S->isLazy()) { 220c94d393aSSam Clegg DEBUG(dbgs() << "resolved by existing lazy\n"); 221c94d393aSSam Clegg auto *AF = cast<ArchiveFile>(S->getFile()); 222c94d393aSSam Clegg AF->addMember(&S->getArchiveSymbol()); 223c94d393aSSam Clegg } else if (S->isDefined()) { 224c94d393aSSam Clegg DEBUG(dbgs() << "resolved by existing\n"); 225b8621596SSam Clegg checkSymbolTypes(*S, *F, *Sym, NewSig); 226c94d393aSSam Clegg } 227c94d393aSSam Clegg return S; 228c94d393aSSam Clegg } 229c94d393aSSam Clegg 230c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) { 231a681a116SSam Clegg DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); 232c94d393aSSam Clegg StringRef Name = Sym->getName(); 233c94d393aSSam Clegg Symbol *S; 234c94d393aSSam Clegg bool WasInserted; 235c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 236c94d393aSSam Clegg if (WasInserted) { 237c94d393aSSam Clegg S->update(Symbol::LazyKind, F); 238c94d393aSSam Clegg S->setArchiveSymbol(*Sym); 239c94d393aSSam Clegg } else if (S->isUndefined()) { 240c94d393aSSam Clegg // There is an existing undefined symbol. The can load from the 241c94d393aSSam Clegg // archive. 242c94d393aSSam Clegg DEBUG(dbgs() << "replacing existing undefined\n"); 243c94d393aSSam Clegg F->addMember(Sym); 244c94d393aSSam Clegg } 245c94d393aSSam Clegg } 246