1c94d393aSSam Clegg //===- SymbolTable.cpp ----------------------------------------------------===// 2c94d393aSSam Clegg // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c94d393aSSam Clegg // 7c94d393aSSam Clegg //===----------------------------------------------------------------------===// 8c94d393aSSam Clegg 9c94d393aSSam Clegg #include "SymbolTable.h" 10c94d393aSSam Clegg #include "Config.h" 115fa274beSSam Clegg #include "InputChunks.h" 12e915a71fSHeejin Ahn #include "InputEvent.h" 1393102974SSam 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; 2345218f4aSSam Clegg using namespace llvm::object; 24c94d393aSSam Clegg using namespace lld; 25c94d393aSSam Clegg using namespace lld::wasm; 26c94d393aSSam Clegg 27c94d393aSSam Clegg SymbolTable *lld::wasm::Symtab; 28c94d393aSSam Clegg 29c94d393aSSam Clegg void SymbolTable::addFile(InputFile *File) { 30c94d393aSSam Clegg log("Processing: " + toString(File)); 311f3f774fSSam Clegg if (Config->Trace) 321f3f774fSSam Clegg message(toString(File)); 33c94d393aSSam Clegg File->parse(); 34c94d393aSSam Clegg 35c729c1b4SSam Clegg // LLVM bitcode file 36c729c1b4SSam Clegg if (auto *F = dyn_cast<BitcodeFile>(File)) 37c729c1b4SSam Clegg BitcodeFiles.push_back(F); 38c729c1b4SSam Clegg else if (auto *F = dyn_cast<ObjFile>(File)) 39c94d393aSSam Clegg ObjectFiles.push_back(F); 40c94d393aSSam Clegg } 41c94d393aSSam Clegg 42c729c1b4SSam Clegg // This function is where all the optimizations of link-time 43c729c1b4SSam Clegg // optimization happens. When LTO is in use, some input files are 44c729c1b4SSam Clegg // not in native object file format but in the LLVM bitcode format. 45c729c1b4SSam Clegg // This function compiles bitcode files into a few big native files 46c729c1b4SSam Clegg // using LLVM functions and replaces bitcode symbols with the results. 47c729c1b4SSam Clegg // Because all bitcode files that the program consists of are passed 48c729c1b4SSam Clegg // to the compiler at once, it can do whole-program optimization. 49c729c1b4SSam Clegg void SymbolTable::addCombinedLTOObject() { 50c729c1b4SSam Clegg if (BitcodeFiles.empty()) 51c729c1b4SSam Clegg return; 52c729c1b4SSam Clegg 53c729c1b4SSam Clegg // Compile bitcode files and replace bitcode symbols. 54c729c1b4SSam Clegg LTO.reset(new BitcodeCompiler); 55c729c1b4SSam Clegg for (BitcodeFile *F : BitcodeFiles) 56c729c1b4SSam Clegg LTO->add(*F); 57c729c1b4SSam Clegg 58c729c1b4SSam Clegg for (StringRef Filename : LTO->compile()) { 59c729c1b4SSam Clegg auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp")); 60c729c1b4SSam Clegg Obj->parse(); 61c729c1b4SSam Clegg ObjectFiles.push_back(Obj); 62c729c1b4SSam Clegg } 63c729c1b4SSam Clegg } 64c729c1b4SSam Clegg 65c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() { 6674fe0ba1SSam Clegg for (Symbol *Sym : SymVector) { 67c729c1b4SSam Clegg if (!Sym->isUndefined() || Sym->isWeak()) 68c729c1b4SSam Clegg continue; 69c729c1b4SSam Clegg if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0) 70c729c1b4SSam Clegg continue; 71c729c1b4SSam Clegg if (!Sym->IsUsedInRegularObj) 72c729c1b4SSam Clegg continue; 7347e2b6b2SSam Clegg error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym)); 74c94d393aSSam Clegg } 75c94d393aSSam Clegg } 76c94d393aSSam Clegg 77c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) { 781f3f774fSSam Clegg auto It = SymMap.find(CachedHashStringRef(Name)); 791f3f774fSSam Clegg if (It == SymMap.end() || It->second == -1) 801f3f774fSSam Clegg return nullptr; 811f3f774fSSam Clegg return SymVector[It->second]; 821f3f774fSSam Clegg } 831f3f774fSSam Clegg 841f3f774fSSam Clegg std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) { 851f3f774fSSam Clegg bool Trace = false; 861f3f774fSSam Clegg auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); 871f3f774fSSam Clegg int &SymIndex = P.first->second; 881f3f774fSSam Clegg bool IsNew = P.second; 891f3f774fSSam Clegg if (SymIndex == -1) { 901f3f774fSSam Clegg SymIndex = SymVector.size(); 911f3f774fSSam Clegg Trace = true; 921f3f774fSSam Clegg IsNew = true; 931f3f774fSSam Clegg } 941f3f774fSSam Clegg 951f3f774fSSam Clegg if (!IsNew) 961f3f774fSSam Clegg return {SymVector[SymIndex], false}; 971f3f774fSSam Clegg 981f3f774fSSam Clegg Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 991f3f774fSSam Clegg Sym->IsUsedInRegularObj = false; 1001f3f774fSSam Clegg Sym->Traced = Trace; 1011f3f774fSSam Clegg SymVector.emplace_back(Sym); 1021f3f774fSSam Clegg return {Sym, true}; 103c94d393aSSam Clegg } 104c94d393aSSam Clegg 105*230dc11dSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, 106*230dc11dSSam Clegg const InputFile *File) { 1071f3f774fSSam Clegg Symbol *S; 1081f3f774fSSam Clegg bool WasInserted; 1091f3f774fSSam Clegg std::tie(S, WasInserted) = insertName(Name); 1101f3f774fSSam Clegg 1114c2cbfe6SSam Clegg if (!File || File->kind() == InputFile::ObjectKind) 1121f3f774fSSam Clegg S->IsUsedInRegularObj = true; 1131f3f774fSSam Clegg 1141f3f774fSSam Clegg return {S, WasInserted}; 115c94d393aSSam Clegg } 116c94d393aSSam Clegg 117e3498ec5SRui Ueyama static void reportTypeError(const Symbol *Existing, const InputFile *File, 1183876d89aSSam Clegg llvm::wasm::WasmSymbolType Type) { 119e3498ec5SRui Ueyama error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " + 120e3498ec5SRui Ueyama toString(Existing->getWasmType()) + " in " + 1213876d89aSSam Clegg toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) + 1223876d89aSSam Clegg " in " + toString(File)); 123e3498ec5SRui Ueyama } 124e3498ec5SRui Ueyama 1256f4286fbSHeejin Ahn // Check the type of new symbol matches that of the symbol is replacing. 1266f4286fbSHeejin Ahn // For functions this can also involve verifying that the signatures match. 127cefbf9acSSam Clegg static void checkFunctionType(Symbol *Existing, const InputFile *File, 128e3498ec5SRui Ueyama const WasmSignature *NewSig) { 12965d6380cSSam Clegg auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing); 13065d6380cSSam Clegg if (!ExistingFunction) { 1313876d89aSSam Clegg reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION); 132e3498ec5SRui Ueyama return; 133e3498ec5SRui Ueyama } 134e3498ec5SRui Ueyama 135cefbf9acSSam Clegg if (!NewSig) 136cefbf9acSSam Clegg return; 137cefbf9acSSam Clegg 138e915a71fSHeejin Ahn const WasmSignature *OldSig = ExistingFunction->Signature; 139cefbf9acSSam Clegg if (!OldSig) { 140e915a71fSHeejin Ahn ExistingFunction->Signature = NewSig; 141cefbf9acSSam Clegg return; 142cefbf9acSSam Clegg } 143cefbf9acSSam Clegg 144cefbf9acSSam Clegg if (*NewSig != *OldSig) 145ffd0aaf8SSam Clegg warn("function signature mismatch: " + Existing->getName() + 146e3498ec5SRui Ueyama "\n>>> defined as " + toString(*OldSig) + " in " + 147e3498ec5SRui Ueyama toString(Existing->getFile()) + "\n>>> defined as " + 148ffd0aaf8SSam Clegg toString(*NewSig) + " in " + toString(File)); 149e3498ec5SRui Ueyama } 150e3498ec5SRui Ueyama 151e3498ec5SRui Ueyama static void checkGlobalType(const Symbol *Existing, const InputFile *File, 152e3498ec5SRui Ueyama const WasmGlobalType *NewType) { 153e3498ec5SRui Ueyama if (!isa<GlobalSymbol>(Existing)) { 1543876d89aSSam Clegg reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL); 155b8621596SSam Clegg return; 156b8621596SSam Clegg } 157b8621596SSam Clegg 158e3498ec5SRui Ueyama const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType(); 159e3498ec5SRui Ueyama if (*NewType != *OldType) { 160e3498ec5SRui Ueyama error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " + 161e3498ec5SRui Ueyama toString(*OldType) + " in " + toString(Existing->getFile()) + 162e3498ec5SRui Ueyama "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); 163c94d393aSSam Clegg } 16424b3dcd4SSam Clegg } 16524b3dcd4SSam Clegg 166e915a71fSHeejin Ahn static void checkEventType(const Symbol *Existing, const InputFile *File, 167e915a71fSHeejin Ahn const WasmEventType *NewType, 168e915a71fSHeejin Ahn const WasmSignature *NewSig) { 169e915a71fSHeejin Ahn auto ExistingEvent = dyn_cast<EventSymbol>(Existing); 170e915a71fSHeejin Ahn if (!isa<EventSymbol>(Existing)) { 171e915a71fSHeejin Ahn reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT); 172e915a71fSHeejin Ahn return; 173e915a71fSHeejin Ahn } 174e915a71fSHeejin Ahn 175e915a71fSHeejin Ahn const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType(); 176e915a71fSHeejin Ahn const WasmSignature *OldSig = ExistingEvent->Signature; 177e915a71fSHeejin Ahn if (NewType->Attribute != OldType->Attribute) 178e915a71fSHeejin Ahn error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " + 179e915a71fSHeejin Ahn toString(*OldType) + " in " + toString(Existing->getFile()) + 180e915a71fSHeejin Ahn "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); 181e915a71fSHeejin Ahn if (*NewSig != *OldSig) 182e915a71fSHeejin Ahn warn("Event signature mismatch: " + Existing->getName() + 183e915a71fSHeejin Ahn "\n>>> defined as " + toString(*OldSig) + " in " + 184e915a71fSHeejin Ahn toString(Existing->getFile()) + "\n>>> defined as " + 185e915a71fSHeejin Ahn toString(*NewSig) + " in " + toString(File)); 186e915a71fSHeejin Ahn } 187e915a71fSHeejin Ahn 188e3498ec5SRui Ueyama static void checkDataType(const Symbol *Existing, const InputFile *File) { 189e3498ec5SRui Ueyama if (!isa<DataSymbol>(Existing)) 1903876d89aSSam Clegg reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA); 191e3498ec5SRui Ueyama } 192e3498ec5SRui Ueyama 193dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, 194ebda41f8SNicholas Wilson uint32_t Flags, 195ebda41f8SNicholas Wilson InputFunction *Function) { 196e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n"); 197b961abc8SRui Ueyama assert(!find(Name)); 198ebda41f8SNicholas Wilson SyntheticFunctions.emplace_back(Function); 1994c2cbfe6SSam Clegg return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name, 2004c2cbfe6SSam Clegg Flags, nullptr, Function); 20150686856SSam Clegg } 20250686856SSam Clegg 20300245539SSam Clegg DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name, 20400245539SSam Clegg uint32_t Flags) { 205e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n"); 206b961abc8SRui Ueyama assert(!find(Name)); 2074c2cbfe6SSam Clegg return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags); 208c94d393aSSam Clegg } 209c94d393aSSam Clegg 21093102974SSam Clegg DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, 21193102974SSam Clegg InputGlobal *Global) { 212e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global 213e7245b42SNicola Zaghen << "\n"); 214b961abc8SRui Ueyama assert(!find(Name)); 215ebda41f8SNicholas Wilson SyntheticGlobals.emplace_back(Global); 2164c2cbfe6SSam Clegg return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags, 2174c2cbfe6SSam Clegg nullptr, Global); 21893102974SSam Clegg } 21993102974SSam Clegg 220e3498ec5SRui Ueyama static bool shouldReplace(const Symbol *Existing, InputFile *NewFile, 221e3498ec5SRui Ueyama uint32_t NewFlags) { 222c03c9040SRui Ueyama // If existing symbol is undefined, replace it. 223e3498ec5SRui Ueyama if (!Existing->isDefined()) { 224e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 225e3498ec5SRui Ueyama << Existing->getName() << "\n"); 226c03c9040SRui Ueyama return true; 227c03c9040SRui Ueyama } 228c03c9040SRui Ueyama 229c03c9040SRui Ueyama // Now we have two defined symbols. If the new one is weak, we can ignore it. 230c03c9040SRui Ueyama if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 231e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 232c03c9040SRui Ueyama return false; 233c03c9040SRui Ueyama } 234c03c9040SRui Ueyama 235c03c9040SRui Ueyama // If the existing symbol is weak, we should replace it. 236e3498ec5SRui Ueyama if (Existing->isWeak()) { 237e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 238c03c9040SRui Ueyama return true; 239c03c9040SRui Ueyama } 240c03c9040SRui Ueyama 241c03c9040SRui Ueyama // Neither symbol is week. They conflict. 242e3498ec5SRui Ueyama error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + 243e3498ec5SRui Ueyama toString(Existing->getFile()) + "\n>>> defined in " + 244e3498ec5SRui Ueyama toString(NewFile)); 245c03c9040SRui Ueyama return true; 246b8621596SSam Clegg } 24793e559b1SSam Clegg 24893e559b1SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags, 249e3498ec5SRui Ueyama InputFile *File, 250e3498ec5SRui Ueyama InputFunction *Function) { 2518b0b48f3SSam Clegg LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " [" 2528b0b48f3SSam Clegg << (Function ? toString(Function->Signature) : "none") 2538b0b48f3SSam Clegg << "]\n"); 25493e559b1SSam Clegg Symbol *S; 25593e559b1SSam Clegg bool WasInserted; 2564c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 257c729c1b4SSam Clegg 258e3498ec5SRui Ueyama if (WasInserted || S->isLazy()) { 259e3498ec5SRui Ueyama replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function); 260e3498ec5SRui Ueyama return S; 261e3498ec5SRui Ueyama } 262e3498ec5SRui Ueyama 263c729c1b4SSam Clegg if (Function) 264e3498ec5SRui Ueyama checkFunctionType(S, File, &Function->Signature); 265e3498ec5SRui Ueyama 2668b0b48f3SSam Clegg if (shouldReplace(S, File, Flags)) { 2678b0b48f3SSam Clegg // If the new defined function doesn't have signture (i.e. bitcode 26837b4ee52SSam Clegg // functions) but the old symbol does then preserve the old signature 2698b0b48f3SSam Clegg const WasmSignature *OldSig = nullptr; 2708b0b48f3SSam Clegg if (auto* F = dyn_cast<FunctionSymbol>(S)) 271e915a71fSHeejin Ahn OldSig = F->Signature; 27237b4ee52SSam Clegg if (auto *L = dyn_cast<LazySymbol>(S)) 27337b4ee52SSam Clegg OldSig = L->Signature; 2748b0b48f3SSam Clegg auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function); 275e915a71fSHeejin Ahn if (!NewSym->Signature) 276e915a71fSHeejin Ahn NewSym->Signature = OldSig; 2778b0b48f3SSam Clegg } 27893e559b1SSam Clegg return S; 27993e559b1SSam Clegg } 28093e559b1SSam Clegg 28100245539SSam Clegg Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags, 282e3498ec5SRui Ueyama InputFile *File, InputSegment *Segment, 28393102974SSam Clegg uint32_t Address, uint32_t Size) { 284e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address 285e7245b42SNicola Zaghen << "\n"); 28693e559b1SSam Clegg Symbol *S; 28793e559b1SSam Clegg bool WasInserted; 2884c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 289c729c1b4SSam Clegg 290e3498ec5SRui Ueyama if (WasInserted || S->isLazy()) { 291e3498ec5SRui Ueyama replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); 292e3498ec5SRui Ueyama return S; 293e3498ec5SRui Ueyama } 294e3498ec5SRui Ueyama 295e3498ec5SRui Ueyama checkDataType(S, File); 296e3498ec5SRui Ueyama 297e3498ec5SRui Ueyama if (shouldReplace(S, File, Flags)) 298e3498ec5SRui Ueyama replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); 299c94d393aSSam Clegg return S; 300c94d393aSSam Clegg } 301c94d393aSSam Clegg 30293102974SSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags, 303e3498ec5SRui Ueyama InputFile *File, InputGlobal *Global) { 304e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n"); 3054c2cbfe6SSam Clegg 30693102974SSam Clegg Symbol *S; 30793102974SSam Clegg bool WasInserted; 3084c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 309c729c1b4SSam Clegg 310e3498ec5SRui Ueyama if (WasInserted || S->isLazy()) { 311e3498ec5SRui Ueyama replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); 31293102974SSam Clegg return S; 31393102974SSam Clegg } 31493102974SSam Clegg 315e3498ec5SRui Ueyama checkGlobalType(S, File, &Global->getType()); 316e3498ec5SRui Ueyama 317e3498ec5SRui Ueyama if (shouldReplace(S, File, Flags)) 318e3498ec5SRui Ueyama replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); 319e3498ec5SRui Ueyama return S; 320e3498ec5SRui Ueyama } 321e3498ec5SRui Ueyama 322e915a71fSHeejin Ahn Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags, 323e915a71fSHeejin Ahn InputFile *File, InputEvent *Event) { 324e915a71fSHeejin Ahn LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n"); 325e915a71fSHeejin Ahn 326e915a71fSHeejin Ahn Symbol *S; 327e915a71fSHeejin Ahn bool WasInserted; 328e915a71fSHeejin Ahn std::tie(S, WasInserted) = insert(Name, File); 329e915a71fSHeejin Ahn 330e915a71fSHeejin Ahn if (WasInserted || S->isLazy()) { 331e915a71fSHeejin Ahn replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event); 332e915a71fSHeejin Ahn return S; 333e915a71fSHeejin Ahn } 334e915a71fSHeejin Ahn 335e915a71fSHeejin Ahn checkEventType(S, File, &Event->getType(), &Event->Signature); 336e915a71fSHeejin Ahn 337e915a71fSHeejin Ahn if (shouldReplace(S, File, Flags)) 338e915a71fSHeejin Ahn replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event); 339e915a71fSHeejin Ahn return S; 340e915a71fSHeejin Ahn } 341e915a71fSHeejin Ahn 3429b84eeaaSDan Gohman Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName, 3439b84eeaaSDan Gohman StringRef ImportModule, 3447cc07531SSam Clegg uint32_t Flags, InputFile *File, 345e3498ec5SRui Ueyama const WasmSignature *Sig) { 3468b0b48f3SSam Clegg LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << 3478b0b48f3SSam Clegg " [" << (Sig ? toString(*Sig) : "none") << "]\n"); 348c03c9040SRui Ueyama 349c94d393aSSam Clegg Symbol *S; 350c94d393aSSam Clegg bool WasInserted; 3514c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 352c729c1b4SSam Clegg 353e3498ec5SRui Ueyama if (WasInserted) 3549b84eeaaSDan Gohman replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags, 3559b84eeaaSDan Gohman File, Sig); 356e3498ec5SRui Ueyama else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 357b961abc8SRui Ueyama Lazy->fetch(); 358cefbf9acSSam Clegg else 359e3498ec5SRui Ueyama checkFunctionType(S, File, Sig); 360cefbf9acSSam Clegg 361c03c9040SRui Ueyama return S; 362c03c9040SRui Ueyama } 363c03c9040SRui Ueyama 364e3498ec5SRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags, 365e3498ec5SRui Ueyama InputFile *File) { 366e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n"); 36793102974SSam Clegg 368e3498ec5SRui Ueyama Symbol *S; 369e3498ec5SRui Ueyama bool WasInserted; 3704c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 371f989a92dSSam Clegg 372e3498ec5SRui Ueyama if (WasInserted) 373e3498ec5SRui Ueyama replaceSymbol<UndefinedData>(S, Name, Flags, File); 374e3498ec5SRui Ueyama else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 375b961abc8SRui Ueyama Lazy->fetch(); 376e3498ec5SRui Ueyama else if (S->isDefined()) 377e3498ec5SRui Ueyama checkDataType(S, File); 378c94d393aSSam Clegg return S; 379c94d393aSSam Clegg } 380c94d393aSSam Clegg 3819b84eeaaSDan Gohman Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName, 3829b84eeaaSDan Gohman StringRef ImportModule, uint32_t Flags, 383e3498ec5SRui Ueyama InputFile *File, 384e3498ec5SRui Ueyama const WasmGlobalType *Type) { 385e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n"); 386e3498ec5SRui Ueyama 387e3498ec5SRui Ueyama Symbol *S; 388e3498ec5SRui Ueyama bool WasInserted; 3894c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 390c729c1b4SSam Clegg 391e3498ec5SRui Ueyama if (WasInserted) 3929b84eeaaSDan Gohman replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags, 3939b84eeaaSDan Gohman File, Type); 394e3498ec5SRui Ueyama else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 395b961abc8SRui Ueyama Lazy->fetch(); 396e3498ec5SRui Ueyama else if (S->isDefined()) 397e3498ec5SRui Ueyama checkGlobalType(S, File, Type); 398e3498ec5SRui Ueyama return S; 399e3498ec5SRui Ueyama } 400e3498ec5SRui Ueyama 401e3498ec5SRui Ueyama void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) { 402e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); 403c94d393aSSam Clegg StringRef Name = Sym->getName(); 404c03c9040SRui Ueyama 405c94d393aSSam Clegg Symbol *S; 406c94d393aSSam Clegg bool WasInserted; 4074c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, nullptr); 408c03c9040SRui Ueyama 409c94d393aSSam Clegg if (WasInserted) { 41037b4ee52SSam Clegg replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym); 411c03c9040SRui Ueyama return; 412c03c9040SRui Ueyama } 413c03c9040SRui Ueyama 41437b4ee52SSam Clegg if (!S->isUndefined()) 41537b4ee52SSam Clegg return; 41637b4ee52SSam Clegg 41737b4ee52SSam Clegg // The existing symbol is undefined, load a new one from the archive, 41837b4ee52SSam Clegg // unless the the existing symbol is weak in which case replace the undefined 41937b4ee52SSam Clegg // symbols with a LazySymbol. 42037b4ee52SSam Clegg if (S->isWeak()) { 42137b4ee52SSam Clegg const WasmSignature *OldSig = nullptr; 42237b4ee52SSam Clegg // In the case of an UndefinedFunction we need to preserve the expected 42337b4ee52SSam Clegg // signature. 42437b4ee52SSam Clegg if (auto *F = dyn_cast<UndefinedFunction>(S)) 42537b4ee52SSam Clegg OldSig = F->Signature; 42637b4ee52SSam Clegg LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 42737b4ee52SSam Clegg auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK, 42837b4ee52SSam Clegg File, *Sym); 42937b4ee52SSam Clegg NewSym->Signature = OldSig; 43037b4ee52SSam Clegg return; 43137b4ee52SSam Clegg } 43237b4ee52SSam Clegg 433e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 434e3498ec5SRui Ueyama File->addMember(Sym); 435c94d393aSSam Clegg } 436e0f6fcd0SSam Clegg 437c4d9aa1bSNicholas Wilson bool SymbolTable::addComdat(StringRef Name) { 438c4d9aa1bSNicholas Wilson return Comdats.insert(CachedHashStringRef(Name)).second; 439e0f6fcd0SSam Clegg } 4401f3f774fSSam Clegg 4411f3f774fSSam Clegg // Set a flag for --trace-symbol so that we can print out a log message 4421f3f774fSSam Clegg // if a new symbol with the same name is inserted into the symbol table. 4431f3f774fSSam Clegg void SymbolTable::trace(StringRef Name) { 4441f3f774fSSam Clegg SymMap.insert({CachedHashStringRef(Name), -1}); 4451f3f774fSSam Clegg } 446*230dc11dSSam Clegg 447*230dc11dSSam Clegg static const uint8_t UnreachableFn[] = { 448*230dc11dSSam Clegg 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 449*230dc11dSSam Clegg 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 450*230dc11dSSam Clegg }; 451*230dc11dSSam Clegg 452*230dc11dSSam Clegg // Replace the given symbol body with an unreachable function. 453*230dc11dSSam Clegg // This is used by handleWeakUndefines in order to generate a callable 454*230dc11dSSam Clegg // equivalent of an undefined function. 455*230dc11dSSam Clegg InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym, 456*230dc11dSSam Clegg const WasmSignature &Sig, 457*230dc11dSSam Clegg StringRef DebugName) { 458*230dc11dSSam Clegg auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName); 459*230dc11dSSam Clegg Func->setBody(UnreachableFn); 460*230dc11dSSam Clegg SyntheticFunctions.emplace_back(Func); 461*230dc11dSSam Clegg replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr, Func); 462*230dc11dSSam Clegg return Func; 463*230dc11dSSam Clegg } 464*230dc11dSSam Clegg 465*230dc11dSSam Clegg // For weak undefined functions, there may be "call" instructions that reference 466*230dc11dSSam Clegg // the symbol. In this case, we need to synthesise a dummy/stub function that 467*230dc11dSSam Clegg // will abort at runtime, so that relocations can still provided an operand to 468*230dc11dSSam Clegg // the call instruction that passes Wasm validation. 469*230dc11dSSam Clegg void SymbolTable::handleWeakUndefines() { 470*230dc11dSSam Clegg for (Symbol *Sym : getSymbols()) { 471*230dc11dSSam Clegg if (!Sym->isUndefWeak()) 472*230dc11dSSam Clegg continue; 473*230dc11dSSam Clegg 474*230dc11dSSam Clegg const WasmSignature *Sig = nullptr; 475*230dc11dSSam Clegg 476*230dc11dSSam Clegg if (auto *FuncSym = dyn_cast<FunctionSymbol>(Sym)) { 477*230dc11dSSam Clegg // It is possible for undefined functions not to have a signature (eg. if 478*230dc11dSSam Clegg // added via "--undefined"), but weak undefined ones do have a signature. 479*230dc11dSSam Clegg assert(FuncSym->Signature); 480*230dc11dSSam Clegg Sig = FuncSym->Signature; 481*230dc11dSSam Clegg } else if (auto *LazySym = dyn_cast<LazySymbol>(Sym)) { 482*230dc11dSSam Clegg // Lazy symbols may not be functions and therefore can have a null 483*230dc11dSSam Clegg // signature. 484*230dc11dSSam Clegg Sig = LazySym->Signature; 485*230dc11dSSam Clegg } 486*230dc11dSSam Clegg 487*230dc11dSSam Clegg if (!Sig) 488*230dc11dSSam Clegg continue; 489*230dc11dSSam Clegg 490*230dc11dSSam Clegg // Add a synthetic dummy for weak undefined functions. These dummies will 491*230dc11dSSam Clegg // be GC'd if not used as the target of any "call" instructions. 492*230dc11dSSam Clegg StringRef DebugName = Saver.save("undefined:" + toString(*Sym)); 493*230dc11dSSam Clegg InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName); 494*230dc11dSSam Clegg // Ensure it compares equal to the null pointer, and so that table relocs 495*230dc11dSSam Clegg // don't pull in the stub body (only call-operand relocs should do that). 496*230dc11dSSam Clegg Func->setTableIndex(0); 497*230dc11dSSam Clegg // Hide our dummy to prevent export. 498*230dc11dSSam Clegg Sym->setHidden(true); 499*230dc11dSSam Clegg } 500*230dc11dSSam Clegg } 501