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 #include "Config.h" 125fa274beSSam Clegg #include "InputChunks.h" 13*93102974SSam Clegg #include "InputGlobal.h" 14b8621596SSam Clegg #include "WriterUtils.h" 15c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h" 162017d52bSRui Ueyama #include "lld/Common/Memory.h" 177d67dd11SRui Ueyama #include "llvm/ADT/SetVector.h" 18c94d393aSSam Clegg 19c94d393aSSam Clegg #define DEBUG_TYPE "lld" 20c94d393aSSam Clegg 21c94d393aSSam Clegg using namespace llvm; 2220db381bSSam Clegg using namespace llvm::wasm; 23c94d393aSSam Clegg using namespace lld; 24c94d393aSSam Clegg using namespace lld::wasm; 25c94d393aSSam Clegg 26c94d393aSSam Clegg SymbolTable *lld::wasm::Symtab; 27c94d393aSSam Clegg 28c94d393aSSam Clegg void SymbolTable::addFile(InputFile *File) { 29c94d393aSSam Clegg log("Processing: " + toString(File)); 30c94d393aSSam Clegg File->parse(); 31c94d393aSSam Clegg 32c94d393aSSam Clegg if (auto *F = dyn_cast<ObjFile>(File)) 33c94d393aSSam Clegg ObjectFiles.push_back(F); 34c94d393aSSam Clegg } 35c94d393aSSam Clegg 36c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() { 377d67dd11SRui Ueyama SetVector<Symbol *> Undefs; 3874fe0ba1SSam Clegg for (Symbol *Sym : SymVector) { 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}; 69dfb0b2c7SSam Clegg Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 7074fe0ba1SSam Clegg SymVector.emplace_back(Sym); 71c94d393aSSam Clegg return {Sym, true}; 72c94d393aSSam Clegg } 73c94d393aSSam Clegg 74b8621596SSam Clegg // Check the type of new symbol matches that of the symbol is replacing. 75b8621596SSam Clegg // For functions this can also involve verifying that the signatures match. 76b8621596SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, 77*93102974SSam Clegg WasmSymbolType NewType, 78*93102974SSam Clegg const WasmSignature *NewFunctionSig, 79*93102974SSam Clegg const WasmGlobalType *NewGlobalType) { 80b8621596SSam Clegg if (Existing.isLazy()) 81c94d393aSSam Clegg return; 82c94d393aSSam Clegg 83*93102974SSam Clegg WasmSymbolType ExistingType = Existing.getWasmType(); 84*93102974SSam Clegg 85b8621596SSam Clegg // First check the symbol types match (i.e. either both are function 86b8621596SSam Clegg // symbols or both are data symbols). 87*93102974SSam Clegg if (NewType != ExistingType) { 8820db381bSSam Clegg error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " + 89*93102974SSam Clegg toString(ExistingType) + " in " + toString(Existing.getFile()) + 90*93102974SSam Clegg "\n>>> defined as " + toString(NewType) + " in " + F.getName()); 91b8621596SSam Clegg return; 92b8621596SSam Clegg } 93b8621596SSam Clegg 94*93102974SSam Clegg // For function/global symbols, optionally check the type matches too. 95*93102974SSam Clegg if (NewType == WASM_SYMBOL_TYPE_DATA || !Config->CheckSignatures) 96c94d393aSSam Clegg return; 97dfb0b2c7SSam Clegg 98*93102974SSam Clegg DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n"); 993f8db988SSam Clegg 100*93102974SSam Clegg auto ReportError = [&](const Twine &Old, const Twine &New) { 101*93102974SSam Clegg error(toString(NewType) + " type mismatch: " + Existing.getName() + 102*93102974SSam Clegg "\n>>> defined as " + Old + " in " + toString(Existing.getFile()) + 103*93102974SSam Clegg "\n>>> defined as " + New + " in " + F.getName()); 104*93102974SSam Clegg }; 105*93102974SSam Clegg 106*93102974SSam Clegg if (NewType == WASM_SYMBOL_TYPE_FUNCTION) { 10731de2f0cSSam Clegg // Skip the signature check if the existing function has no signature (e.g. 10831de2f0cSSam Clegg // if it is an undefined symbol generated by --undefined command line flag). 109*93102974SSam Clegg auto &Sym = cast<FunctionSymbol>(Existing); 110*93102974SSam Clegg const WasmSignature *OldSig = Sym.getFunctionType(); 111*93102974SSam Clegg if (!OldSig) 11231de2f0cSSam Clegg return; 113c94d393aSSam Clegg 114*93102974SSam Clegg assert(NewFunctionSig); 115*93102974SSam Clegg if (*NewFunctionSig == *OldSig) 116b8621596SSam Clegg return; 117b8621596SSam Clegg 118*93102974SSam Clegg ReportError(toString(*OldSig), toString(*NewFunctionSig)); 119*93102974SSam Clegg } else { 120*93102974SSam Clegg auto &Sym = cast<GlobalSymbol>(Existing); 121*93102974SSam Clegg 122*93102974SSam Clegg assert(NewGlobalType != nullptr); 123*93102974SSam Clegg const WasmGlobalType *OldType = Sym.getGlobalType(); 124*93102974SSam Clegg if (*NewGlobalType == *OldType) 125*93102974SSam Clegg return; 126*93102974SSam Clegg 127*93102974SSam Clegg ReportError(toString(*OldType), toString(*NewGlobalType)); 128c94d393aSSam Clegg } 12924b3dcd4SSam Clegg } 13024b3dcd4SSam Clegg 131dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, 13250686856SSam Clegg const WasmSignature *Type, 13350686856SSam Clegg uint32_t Flags) { 134a189230bSSam Clegg DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n"); 13550686856SSam Clegg Symbol *S; 13650686856SSam Clegg bool WasInserted; 13750686856SSam Clegg std::tie(S, WasInserted) = insert(Name); 138a189230bSSam Clegg assert(WasInserted); 139dfb0b2c7SSam Clegg return replaceSymbol<DefinedFunction>(S, Name, Flags, Type); 14050686856SSam Clegg } 14150686856SSam Clegg 14200245539SSam Clegg DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name, 14300245539SSam Clegg uint32_t Flags) { 14400245539SSam Clegg DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n"); 145c94d393aSSam Clegg Symbol *S; 146c94d393aSSam Clegg bool WasInserted; 147c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 148a189230bSSam Clegg assert(WasInserted); 14900245539SSam Clegg return replaceSymbol<DefinedData>(S, Name, Flags); 150c94d393aSSam Clegg } 151c94d393aSSam Clegg 152*93102974SSam Clegg DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, 153*93102974SSam Clegg InputGlobal *Global) { 154*93102974SSam Clegg DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global << "\n"); 155*93102974SSam Clegg Symbol *S; 156*93102974SSam Clegg bool WasInserted; 157*93102974SSam Clegg std::tie(S, WasInserted) = insert(Name); 158*93102974SSam Clegg assert(WasInserted); 159*93102974SSam Clegg return replaceSymbol<DefinedGlobal>(S, Name, Flags, nullptr, Global); 160*93102974SSam Clegg } 161*93102974SSam Clegg 162f60b0d5cSSam Clegg static bool shouldReplace(const Symbol &Existing, InputFile *NewFile, 163*93102974SSam Clegg WasmSymbolType NewType, uint32_t NewFlags, 164*93102974SSam Clegg const WasmSignature *NewFuncType = nullptr, 165*93102974SSam Clegg const WasmGlobalType *NewGlobalType = nullptr) { 166*93102974SSam Clegg 167c03c9040SRui Ueyama // If existing symbol is lazy, replace it without checking types since 168b8621596SSam Clegg // lazy symbols don't have any type information. 169c03c9040SRui Ueyama if (Existing.isLazy()) { 17093e559b1SSam Clegg DEBUG(dbgs() << "replacing existing lazy symbol: " << Existing.getName() 17193e559b1SSam Clegg << "\n"); 172c03c9040SRui Ueyama return true; 173c94d393aSSam Clegg } 174c94d393aSSam Clegg 175c03c9040SRui Ueyama // Now we have two wasm symbols, and all wasm symbols that have the same 176c03c9040SRui Ueyama // symbol name must have the same type, even if they are undefined. This 177c03c9040SRui Ueyama // is different from ELF because symbol types are not that significant 178c03c9040SRui Ueyama // in ELF, and undefined symbols in ELF don't have type in the first place. 179*93102974SSam Clegg checkSymbolTypes(Existing, *NewFile, NewType, NewFuncType, NewGlobalType); 18093e559b1SSam Clegg 181c03c9040SRui Ueyama // If existing symbol is undefined, replace it. 182c03c9040SRui Ueyama if (!Existing.isDefined()) { 183c03c9040SRui Ueyama DEBUG(dbgs() << "resolving existing undefined symbol: " 184c03c9040SRui Ueyama << Existing.getName() << "\n"); 185c03c9040SRui Ueyama return true; 186c03c9040SRui Ueyama } 187c03c9040SRui Ueyama 188c03c9040SRui Ueyama // Now we have two defined symbols. If the new one is weak, we can ignore it. 189c03c9040SRui Ueyama if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 190c03c9040SRui Ueyama DEBUG(dbgs() << "existing symbol takes precedence\n"); 191c03c9040SRui Ueyama return false; 192c03c9040SRui Ueyama } 193c03c9040SRui Ueyama 194c03c9040SRui Ueyama // If the existing symbol is weak, we should replace it. 195c03c9040SRui Ueyama if (Existing.isWeak()) { 196c03c9040SRui Ueyama DEBUG(dbgs() << "replacing existing weak symbol\n"); 197c03c9040SRui Ueyama return true; 198c03c9040SRui Ueyama } 199c03c9040SRui Ueyama 200c03c9040SRui Ueyama // Neither symbol is week. They conflict. 201c03c9040SRui Ueyama error("duplicate symbol: " + toString(Existing) + "\n>>> defined in " + 202c03c9040SRui Ueyama toString(Existing.getFile()) + "\n>>> defined in " + toString(NewFile)); 203c03c9040SRui Ueyama return true; 204b8621596SSam Clegg } 20593e559b1SSam Clegg 20693e559b1SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags, 20793e559b1SSam Clegg InputFile *F, InputFunction *Function) { 20893e559b1SSam Clegg DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n"); 20993e559b1SSam Clegg Symbol *S; 21093e559b1SSam Clegg bool WasInserted; 21193e559b1SSam Clegg std::tie(S, WasInserted) = insert(Name); 212*93102974SSam Clegg if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_FUNCTION, Flags, 213*93102974SSam Clegg &Function->Signature)) 21493e559b1SSam Clegg replaceSymbol<DefinedFunction>(S, Name, Flags, F, Function); 21593e559b1SSam Clegg return S; 21693e559b1SSam Clegg } 21793e559b1SSam Clegg 21800245539SSam Clegg Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags, 21993e559b1SSam Clegg InputFile *F, InputSegment *Segment, 220*93102974SSam Clegg uint32_t Address, uint32_t Size) { 22100245539SSam Clegg DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address << "\n"); 22293e559b1SSam Clegg Symbol *S; 22393e559b1SSam Clegg bool WasInserted; 22493e559b1SSam Clegg std::tie(S, WasInserted) = insert(Name); 225*93102974SSam Clegg if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_DATA, Flags)) 226*93102974SSam Clegg replaceSymbol<DefinedData>(S, Name, Flags, F, Segment, Address, Size); 227c94d393aSSam Clegg return S; 228c94d393aSSam Clegg } 229c94d393aSSam Clegg 230*93102974SSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags, 231*93102974SSam Clegg InputFile *F, InputGlobal *Global) { 232*93102974SSam Clegg DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n"); 233*93102974SSam Clegg Symbol *S; 234*93102974SSam Clegg bool WasInserted; 235*93102974SSam Clegg std::tie(S, WasInserted) = insert(Name); 236*93102974SSam Clegg if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_GLOBAL, Flags, 237*93102974SSam Clegg nullptr, &Global->getType())) 238*93102974SSam Clegg replaceSymbol<DefinedGlobal>(S, Name, Flags, F, Global); 239*93102974SSam Clegg return S; 240*93102974SSam Clegg } 241*93102974SSam Clegg 242*93102974SSam Clegg Symbol *SymbolTable::addUndefined(StringRef Name, WasmSymbolType Type, 24320db381bSSam Clegg uint32_t Flags, InputFile *F, 244*93102974SSam Clegg const WasmSignature *FunctionType, 245*93102974SSam Clegg const WasmGlobalType *GlobalType) { 246*93102974SSam Clegg DEBUG(dbgs() << "addUndefined type=" << Type << ": " << Name << "\n"); 247c03c9040SRui Ueyama 248c94d393aSSam Clegg Symbol *S; 249c94d393aSSam Clegg bool WasInserted; 25020db381bSSam Clegg std::tie(S, WasInserted) = insert(Name); 251c03c9040SRui Ueyama 252c94d393aSSam Clegg if (WasInserted) { 253*93102974SSam Clegg switch (Type) { 254*93102974SSam Clegg case WASM_SYMBOL_TYPE_FUNCTION: 255*93102974SSam Clegg replaceSymbol<UndefinedFunction>(S, Name, Flags, F, FunctionType); 256*93102974SSam Clegg break; 257*93102974SSam Clegg case WASM_SYMBOL_TYPE_GLOBAL: 258*93102974SSam Clegg replaceSymbol<UndefinedGlobal>(S, Name, Flags, F, GlobalType); 259*93102974SSam Clegg break; 260*93102974SSam Clegg case WASM_SYMBOL_TYPE_DATA: 26100245539SSam Clegg replaceSymbol<UndefinedData>(S, Name, Flags, F); 262*93102974SSam Clegg break; 263*93102974SSam Clegg } 264c03c9040SRui Ueyama return S; 265c03c9040SRui Ueyama } 266c03c9040SRui Ueyama 267c03c9040SRui Ueyama if (auto *Lazy = dyn_cast<LazySymbol>(S)) { 268c94d393aSSam Clegg DEBUG(dbgs() << "resolved by existing lazy\n"); 269c03c9040SRui Ueyama cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol()); 270c03c9040SRui Ueyama return S; 271c03c9040SRui Ueyama } 272c03c9040SRui Ueyama 273c03c9040SRui Ueyama if (S->isDefined()) { 274c94d393aSSam Clegg DEBUG(dbgs() << "resolved by existing\n"); 275*93102974SSam Clegg checkSymbolTypes(*S, *F, Type, FunctionType, GlobalType); 276c94d393aSSam Clegg } 277*93102974SSam Clegg 278c94d393aSSam Clegg return S; 279c94d393aSSam Clegg } 280c94d393aSSam Clegg 281c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) { 282a681a116SSam Clegg DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); 283c94d393aSSam Clegg StringRef Name = Sym->getName(); 284c03c9040SRui Ueyama 285c94d393aSSam Clegg Symbol *S; 286c94d393aSSam Clegg bool WasInserted; 287c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 288c03c9040SRui Ueyama 289c94d393aSSam Clegg if (WasInserted) { 290dfb0b2c7SSam Clegg replaceSymbol<LazySymbol>(S, Name, F, *Sym); 291c03c9040SRui Ueyama return; 292c03c9040SRui Ueyama } 293c03c9040SRui Ueyama 294c03c9040SRui Ueyama // If there is an existing undefined symbol, load a new one from the archive. 295c03c9040SRui Ueyama if (S->isUndefined()) { 296c94d393aSSam Clegg DEBUG(dbgs() << "replacing existing undefined\n"); 297c94d393aSSam Clegg F->addMember(Sym); 298c94d393aSSam Clegg } 299c94d393aSSam Clegg } 300e0f6fcd0SSam Clegg 301e0f6fcd0SSam Clegg bool SymbolTable::addComdat(StringRef Name, ObjFile *F) { 302e0f6fcd0SSam Clegg DEBUG(dbgs() << "addComdat: " << Name << "\n"); 303e0f6fcd0SSam Clegg ObjFile *&File = ComdatMap[CachedHashStringRef(Name)]; 304e0f6fcd0SSam Clegg if (File) { 305e0f6fcd0SSam Clegg DEBUG(dbgs() << "COMDAT already defined\n"); 306e0f6fcd0SSam Clegg return false; 307e0f6fcd0SSam Clegg } 308e0f6fcd0SSam Clegg File = F; 309e0f6fcd0SSam Clegg return true; 310e0f6fcd0SSam Clegg } 311e0f6fcd0SSam Clegg 312e0f6fcd0SSam Clegg ObjFile *SymbolTable::findComdat(StringRef Name) const { 313e0f6fcd0SSam Clegg auto It = ComdatMap.find(CachedHashStringRef(Name)); 314e0f6fcd0SSam Clegg return It == ComdatMap.end() ? nullptr : It->second; 315e0f6fcd0SSam Clegg } 316