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" 135fa274beSSam Clegg #include "InputChunks.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}; 69*dfb0b2c7SSam Clegg Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 7074fe0ba1SSam Clegg SymVector.emplace_back(Sym); 71c94d393aSSam Clegg return {Sym, true}; 72c94d393aSSam Clegg } 73c94d393aSSam Clegg 74c94d393aSSam Clegg void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { 75c94d393aSSam Clegg error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + 76c94d393aSSam Clegg toString(Existing->getFile()) + "\n>>> defined in " + 77e2ed092eSSam Clegg toString(NewFile)); 78c94d393aSSam Clegg } 79c94d393aSSam Clegg 80b8621596SSam Clegg // Check the type of new symbol matches that of the symbol is replacing. 81b8621596SSam Clegg // For functions this can also involve verifying that the signatures match. 82b8621596SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, 83*dfb0b2c7SSam Clegg bool NewIsFunction, const WasmSignature *NewSig) { 84b8621596SSam Clegg if (Existing.isLazy()) 85c94d393aSSam Clegg return; 86c94d393aSSam Clegg 87b8621596SSam Clegg // First check the symbol types match (i.e. either both are function 88b8621596SSam Clegg // symbols or both are data symbols). 89b8621596SSam Clegg if (Existing.isFunction() != NewIsFunction) { 9020db381bSSam Clegg error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " + 91b8621596SSam Clegg (Existing.isFunction() ? "Function" : "Global") + " in " + 92b8621596SSam Clegg toString(Existing.getFile()) + "\n>>> defined as " + 93b8621596SSam Clegg (NewIsFunction ? "Function" : "Global") + " in " + F.getName()); 94b8621596SSam Clegg return; 95b8621596SSam Clegg } 96b8621596SSam Clegg 97b8621596SSam Clegg // For function symbols, optionally check the function signature matches too. 98*dfb0b2c7SSam Clegg auto *ExistingFunc = dyn_cast<FunctionSymbol>(&Existing); 99*dfb0b2c7SSam Clegg if (!ExistingFunc || !Config->CheckSignatures) 100c94d393aSSam Clegg return; 101*dfb0b2c7SSam Clegg 10231de2f0cSSam Clegg // Skip the signature check if the existing function has no signature (e.g. 10331de2f0cSSam Clegg // if it is an undefined symbol generated by --undefined command line flag). 104*dfb0b2c7SSam Clegg if (!ExistingFunc->hasFunctionType()) 10531de2f0cSSam Clegg return; 106c94d393aSSam Clegg 107*dfb0b2c7SSam Clegg DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n"); 108b8621596SSam Clegg assert(NewSig); 109b8621596SSam Clegg 110*dfb0b2c7SSam Clegg const WasmSignature &OldSig = ExistingFunc->getFunctionType(); 111b8621596SSam Clegg if (*NewSig == OldSig) 112b8621596SSam Clegg return; 113b8621596SSam Clegg 114*dfb0b2c7SSam Clegg error("function signature mismatch: " + ExistingFunc->getName() + 11520db381bSSam Clegg "\n>>> defined as " + toString(OldSig) + " in " + 116*dfb0b2c7SSam Clegg toString(ExistingFunc->getFile()) + "\n>>> defined as " + 117*dfb0b2c7SSam Clegg toString(*NewSig) + " in " + F.getName()); 118c94d393aSSam Clegg } 119c94d393aSSam Clegg 12024b3dcd4SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, 121*dfb0b2c7SSam Clegg bool IsFunction, const InputChunk *Chunk) { 12224b3dcd4SSam Clegg const WasmSignature *Sig = nullptr; 12324b3dcd4SSam Clegg if (auto *F = dyn_cast_or_null<InputFunction>(Chunk)) 12424b3dcd4SSam Clegg Sig = &F->Signature; 125*dfb0b2c7SSam Clegg return checkSymbolTypes(Existing, F, IsFunction, Sig); 12624b3dcd4SSam Clegg } 12724b3dcd4SSam Clegg 128*dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, 12950686856SSam Clegg const WasmSignature *Type, 13050686856SSam Clegg uint32_t Flags) { 131a189230bSSam Clegg DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n"); 13250686856SSam Clegg Symbol *S; 13350686856SSam Clegg bool WasInserted; 13450686856SSam Clegg std::tie(S, WasInserted) = insert(Name); 135a189230bSSam Clegg assert(WasInserted); 136*dfb0b2c7SSam Clegg return replaceSymbol<DefinedFunction>(S, Name, Flags, Type); 13750686856SSam Clegg } 13850686856SSam Clegg 139*dfb0b2c7SSam Clegg DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags) { 140a189230bSSam Clegg DEBUG(dbgs() << "addSyntheticGlobal: " << Name << "\n"); 141c94d393aSSam Clegg Symbol *S; 142c94d393aSSam Clegg bool WasInserted; 143c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 144a189230bSSam Clegg assert(WasInserted); 145*dfb0b2c7SSam Clegg return replaceSymbol<DefinedGlobal>(S, Name, Flags); 146c94d393aSSam Clegg } 147c94d393aSSam Clegg 148*dfb0b2c7SSam Clegg Symbol *SymbolTable::addDefined(bool IsFunction, StringRef Name, uint32_t Flags, 149*dfb0b2c7SSam Clegg InputFile *F, InputChunk *Chunk, 150fc50c623SSam Clegg uint32_t Address) { 151*dfb0b2c7SSam Clegg if (IsFunction) 152*dfb0b2c7SSam Clegg DEBUG(dbgs() << "addDefined: func:" << Name << "\n"); 153*dfb0b2c7SSam Clegg else 154*dfb0b2c7SSam Clegg DEBUG(dbgs() << "addDefined: global:" << Name << " addr:" << Address 155*dfb0b2c7SSam Clegg << "\n"); 156c94d393aSSam Clegg Symbol *S; 157c94d393aSSam Clegg bool WasInserted; 158*dfb0b2c7SSam Clegg bool Replace = false; 159*dfb0b2c7SSam Clegg bool CheckTypes = false; 160c94d393aSSam Clegg 16120db381bSSam Clegg std::tie(S, WasInserted) = insert(Name); 162c94d393aSSam Clegg if (WasInserted) { 163*dfb0b2c7SSam Clegg Replace = true; 164b8621596SSam Clegg } else if (S->isLazy()) { 165*dfb0b2c7SSam Clegg // Existing symbol is lazy. Replace it without checking types since 166b8621596SSam Clegg // lazy symbols don't have any type information. 16720db381bSSam Clegg DEBUG(dbgs() << "replacing existing lazy symbol: " << Name << "\n"); 168*dfb0b2c7SSam Clegg Replace = true; 169c94d393aSSam Clegg } else if (!S->isDefined()) { 170*dfb0b2c7SSam Clegg // Existing symbol is undefined: replace it, while check types. 17120db381bSSam Clegg DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n"); 172*dfb0b2c7SSam Clegg Replace = true; 173*dfb0b2c7SSam Clegg CheckTypes = true; 17420db381bSSam Clegg } else if ((Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 175c94d393aSSam Clegg // the new symbol is weak we can ignore it 17649ed9262SSam Clegg DEBUG(dbgs() << "existing symbol takes precedence\n"); 177c94d393aSSam Clegg } else if (S->isWeak()) { 178*dfb0b2c7SSam Clegg // the existing symbol is, so we replace it 179c94d393aSSam Clegg DEBUG(dbgs() << "replacing existing weak symbol\n"); 180*dfb0b2c7SSam Clegg Replace = true; 181*dfb0b2c7SSam Clegg CheckTypes = true; 182c94d393aSSam Clegg } else { 18349ed9262SSam Clegg // neither symbol is week. They conflict. 184c94d393aSSam Clegg reportDuplicate(S, F); 185c94d393aSSam Clegg } 186c94d393aSSam Clegg 187*dfb0b2c7SSam Clegg if (Replace) { 188*dfb0b2c7SSam Clegg if (CheckTypes) 189*dfb0b2c7SSam Clegg checkSymbolTypes(*S, *F, IsFunction, Chunk); 190*dfb0b2c7SSam Clegg if (IsFunction) 191*dfb0b2c7SSam Clegg replaceSymbol<DefinedFunction>(S, Name, Flags, F, Chunk); 192*dfb0b2c7SSam Clegg else 193*dfb0b2c7SSam Clegg replaceSymbol<DefinedGlobal>(S, Name, Flags, F, Chunk, Address); 194b8621596SSam Clegg } 195c94d393aSSam Clegg return S; 196c94d393aSSam Clegg } 197c94d393aSSam Clegg 19820db381bSSam Clegg Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind, 19920db381bSSam Clegg uint32_t Flags, InputFile *F, 2008d146bbcSSam Clegg const WasmSignature *Type) { 20120db381bSSam Clegg DEBUG(dbgs() << "addUndefined: " << Name << "\n"); 202c94d393aSSam Clegg Symbol *S; 203c94d393aSSam Clegg bool WasInserted; 20420db381bSSam Clegg std::tie(S, WasInserted) = insert(Name); 205*dfb0b2c7SSam Clegg bool IsFunction = Kind == Symbol::UndefinedFunctionKind; 206c94d393aSSam Clegg if (WasInserted) { 207*dfb0b2c7SSam Clegg if (IsFunction) 208*dfb0b2c7SSam Clegg replaceSymbol<UndefinedFunction>(S, Name, Flags, F, Type); 209*dfb0b2c7SSam Clegg else 210*dfb0b2c7SSam Clegg replaceSymbol<UndefinedGlobal>(S, Name, Flags, F); 211*dfb0b2c7SSam Clegg } else if (auto *LazySym = dyn_cast<LazySymbol>(S)) { 212c94d393aSSam Clegg DEBUG(dbgs() << "resolved by existing lazy\n"); 213*dfb0b2c7SSam Clegg auto *AF = cast<ArchiveFile>(LazySym->getFile()); 214*dfb0b2c7SSam Clegg AF->addMember(&LazySym->getArchiveSymbol()); 215c94d393aSSam Clegg } else if (S->isDefined()) { 216c94d393aSSam Clegg DEBUG(dbgs() << "resolved by existing\n"); 217*dfb0b2c7SSam Clegg checkSymbolTypes(*S, *F, IsFunction, Type); 218c94d393aSSam Clegg } 219c94d393aSSam Clegg return S; 220c94d393aSSam Clegg } 221c94d393aSSam Clegg 222c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) { 223a681a116SSam Clegg DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); 224c94d393aSSam Clegg StringRef Name = Sym->getName(); 225c94d393aSSam Clegg Symbol *S; 226c94d393aSSam Clegg bool WasInserted; 227c94d393aSSam Clegg std::tie(S, WasInserted) = insert(Name); 228c94d393aSSam Clegg if (WasInserted) { 229*dfb0b2c7SSam Clegg replaceSymbol<LazySymbol>(S, Name, F, *Sym); 230c94d393aSSam Clegg } else if (S->isUndefined()) { 231c94d393aSSam Clegg // There is an existing undefined symbol. The can load from the 232c94d393aSSam Clegg // archive. 233c94d393aSSam Clegg DEBUG(dbgs() << "replacing existing undefined\n"); 234c94d393aSSam Clegg F->addMember(Sym); 235c94d393aSSam Clegg } 236c94d393aSSam Clegg } 237e0f6fcd0SSam Clegg 238e0f6fcd0SSam Clegg bool SymbolTable::addComdat(StringRef Name, ObjFile *F) { 239e0f6fcd0SSam Clegg DEBUG(dbgs() << "addComdat: " << Name << "\n"); 240e0f6fcd0SSam Clegg ObjFile *&File = ComdatMap[CachedHashStringRef(Name)]; 241e0f6fcd0SSam Clegg if (File) { 242e0f6fcd0SSam Clegg DEBUG(dbgs() << "COMDAT already defined\n"); 243e0f6fcd0SSam Clegg return false; 244e0f6fcd0SSam Clegg } 245e0f6fcd0SSam Clegg File = F; 246e0f6fcd0SSam Clegg return true; 247e0f6fcd0SSam Clegg } 248e0f6fcd0SSam Clegg 249e0f6fcd0SSam Clegg ObjFile *SymbolTable::findComdat(StringRef Name) const { 250e0f6fcd0SSam Clegg auto It = ComdatMap.find(CachedHashStringRef(Name)); 251e0f6fcd0SSam Clegg return It == ComdatMap.end() ? nullptr : It->second; 252e0f6fcd0SSam Clegg } 253