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" 12a56e5749SAndy Wingo #include "InputElement.h" 13b8621596SSam Clegg #include "WriterUtils.h" 14c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h" 152017d52bSRui Ueyama #include "lld/Common/Memory.h" 167d67dd11SRui Ueyama #include "llvm/ADT/SetVector.h" 17c94d393aSSam Clegg 18c94d393aSSam Clegg #define DEBUG_TYPE "lld" 19c94d393aSSam Clegg 20c94d393aSSam Clegg using namespace llvm; 2120db381bSSam Clegg using namespace llvm::wasm; 2245218f4aSSam Clegg using namespace llvm::object; 23c94d393aSSam Clegg 2433c59abfSFangrui Song namespace lld { 2533c59abfSFangrui Song namespace wasm { 2633c59abfSFangrui Song SymbolTable *symtab; 27c94d393aSSam Clegg 28136d27abSRui Ueyama void SymbolTable::addFile(InputFile *file) { 29136d27abSRui Ueyama log("Processing: " + toString(file)); 30a282a61bSSam Clegg 31a282a61bSSam Clegg // .a file 32136d27abSRui Ueyama if (auto *f = dyn_cast<ArchiveFile>(file)) { 33136d27abSRui Ueyama f->parse(); 34a282a61bSSam Clegg return; 35a282a61bSSam Clegg } 36a282a61bSSam Clegg 37a282a61bSSam Clegg // .so file 38136d27abSRui Ueyama if (auto *f = dyn_cast<SharedFile>(file)) { 39136d27abSRui Ueyama sharedFiles.push_back(f); 40a282a61bSSam Clegg return; 41a282a61bSSam Clegg } 42a282a61bSSam Clegg 43136d27abSRui Ueyama if (config->trace) 44136d27abSRui Ueyama message(toString(file)); 45c94d393aSSam Clegg 46c729c1b4SSam Clegg // LLVM bitcode file 47136d27abSRui Ueyama if (auto *f = dyn_cast<BitcodeFile>(file)) { 48136d27abSRui Ueyama f->parse(); 49136d27abSRui Ueyama bitcodeFiles.push_back(f); 50a282a61bSSam Clegg return; 51a282a61bSSam Clegg } 52a282a61bSSam Clegg 53a282a61bSSam Clegg // Regular object file 54136d27abSRui Ueyama auto *f = cast<ObjFile>(file); 55136d27abSRui Ueyama f->parse(false); 56136d27abSRui Ueyama objectFiles.push_back(f); 57c94d393aSSam Clegg } 58c94d393aSSam Clegg 59c729c1b4SSam Clegg // This function is where all the optimizations of link-time 60c729c1b4SSam Clegg // optimization happens. When LTO is in use, some input files are 61c729c1b4SSam Clegg // not in native object file format but in the LLVM bitcode format. 62c729c1b4SSam Clegg // This function compiles bitcode files into a few big native files 63c729c1b4SSam Clegg // using LLVM functions and replaces bitcode symbols with the results. 64c729c1b4SSam Clegg // Because all bitcode files that the program consists of are passed 65c729c1b4SSam Clegg // to the compiler at once, it can do whole-program optimization. 66c729c1b4SSam Clegg void SymbolTable::addCombinedLTOObject() { 67b062fe18SSam Clegg // Prevent further LTO objects being included 68b062fe18SSam Clegg BitcodeFile::doneLTO = true; 69b062fe18SSam Clegg 70136d27abSRui Ueyama if (bitcodeFiles.empty()) 71c729c1b4SSam Clegg return; 72c729c1b4SSam Clegg 73c729c1b4SSam Clegg // Compile bitcode files and replace bitcode symbols. 74136d27abSRui Ueyama lto.reset(new BitcodeCompiler); 75136d27abSRui Ueyama for (BitcodeFile *f : bitcodeFiles) 76136d27abSRui Ueyama lto->add(*f); 77c729c1b4SSam Clegg 78136d27abSRui Ueyama for (StringRef filename : lto->compile()) { 79136d27abSRui Ueyama auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), ""); 80136d27abSRui Ueyama obj->parse(true); 81136d27abSRui Ueyama objectFiles.push_back(obj); 82c729c1b4SSam Clegg } 83c729c1b4SSam Clegg } 84c729c1b4SSam Clegg 85136d27abSRui Ueyama Symbol *SymbolTable::find(StringRef name) { 86136d27abSRui Ueyama auto it = symMap.find(CachedHashStringRef(name)); 87136d27abSRui Ueyama if (it == symMap.end() || it->second == -1) 881f3f774fSSam Clegg return nullptr; 89136d27abSRui Ueyama return symVector[it->second]; 901f3f774fSSam Clegg } 911f3f774fSSam Clegg 92136d27abSRui Ueyama void SymbolTable::replace(StringRef name, Symbol* sym) { 93136d27abSRui Ueyama auto it = symMap.find(CachedHashStringRef(name)); 94136d27abSRui Ueyama symVector[it->second] = sym; 956540e570SSam Clegg } 966540e570SSam Clegg 97136d27abSRui Ueyama std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) { 98136d27abSRui Ueyama bool trace = false; 99136d27abSRui Ueyama auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 100136d27abSRui Ueyama int &symIndex = p.first->second; 101136d27abSRui Ueyama bool isNew = p.second; 102136d27abSRui Ueyama if (symIndex == -1) { 103136d27abSRui Ueyama symIndex = symVector.size(); 104136d27abSRui Ueyama trace = true; 105136d27abSRui Ueyama isNew = true; 1061f3f774fSSam Clegg } 1071f3f774fSSam Clegg 108136d27abSRui Ueyama if (!isNew) 109136d27abSRui Ueyama return {symVector[symIndex], false}; 1101f3f774fSSam Clegg 111136d27abSRui Ueyama Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 112136d27abSRui Ueyama sym->isUsedInRegularObj = false; 113136d27abSRui Ueyama sym->canInline = true; 114136d27abSRui Ueyama sym->traced = trace; 115064e9907SSam Clegg sym->forceExport = false; 116136d27abSRui Ueyama symVector.emplace_back(sym); 117136d27abSRui Ueyama return {sym, true}; 118c94d393aSSam Clegg } 119c94d393aSSam Clegg 120136d27abSRui Ueyama std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, 121136d27abSRui Ueyama const InputFile *file) { 122136d27abSRui Ueyama Symbol *s; 123136d27abSRui Ueyama bool wasInserted; 124136d27abSRui Ueyama std::tie(s, wasInserted) = insertName(name); 1251f3f774fSSam Clegg 126136d27abSRui Ueyama if (!file || file->kind() == InputFile::ObjectKind) 127136d27abSRui Ueyama s->isUsedInRegularObj = true; 1281f3f774fSSam Clegg 129136d27abSRui Ueyama return {s, wasInserted}; 130c94d393aSSam Clegg } 131c94d393aSSam Clegg 132136d27abSRui Ueyama static void reportTypeError(const Symbol *existing, const InputFile *file, 133136d27abSRui Ueyama llvm::wasm::WasmSymbolType type) { 134136d27abSRui Ueyama error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " + 135136d27abSRui Ueyama toString(existing->getWasmType()) + " in " + 136136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined as " + toString(type) + 137136d27abSRui Ueyama " in " + toString(file)); 138e3498ec5SRui Ueyama } 139e3498ec5SRui Ueyama 1406f4286fbSHeejin Ahn // Check the type of new symbol matches that of the symbol is replacing. 1417c5fcb35SKazuaki Ishizaki // Returns true if the function types match, false is there is a signature 1426540e570SSam Clegg // mismatch. 143136d27abSRui Ueyama static bool signatureMatches(FunctionSymbol *existing, 144136d27abSRui Ueyama const WasmSignature *newSig) { 145136d27abSRui Ueyama const WasmSignature *oldSig = existing->signature; 146d506b0a4SSam Clegg 147d506b0a4SSam Clegg // If either function is missing a signature (this happend for bitcode 148d506b0a4SSam Clegg // symbols) then assume they match. Any mismatch will be reported later 149d506b0a4SSam Clegg // when the LTO objects are added. 150136d27abSRui Ueyama if (!newSig || !oldSig) 1516540e570SSam Clegg return true; 152cefbf9acSSam Clegg 153136d27abSRui Ueyama return *newSig == *oldSig; 154e3498ec5SRui Ueyama } 155e3498ec5SRui Ueyama 156136d27abSRui Ueyama static void checkGlobalType(const Symbol *existing, const InputFile *file, 157136d27abSRui Ueyama const WasmGlobalType *newType) { 158136d27abSRui Ueyama if (!isa<GlobalSymbol>(existing)) { 159136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL); 160b8621596SSam Clegg return; 161b8621596SSam Clegg } 162b8621596SSam Clegg 163136d27abSRui Ueyama const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType(); 164136d27abSRui Ueyama if (*newType != *oldType) { 165136d27abSRui Ueyama error("Global type mismatch: " + existing->getName() + "\n>>> defined as " + 166136d27abSRui Ueyama toString(*oldType) + " in " + toString(existing->getFile()) + 167136d27abSRui Ueyama "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 168c94d393aSSam Clegg } 16924b3dcd4SSam Clegg } 17024b3dcd4SSam Clegg 171136d27abSRui Ueyama static void checkEventType(const Symbol *existing, const InputFile *file, 172136d27abSRui Ueyama const WasmEventType *newType, 173136d27abSRui Ueyama const WasmSignature *newSig) { 174136d27abSRui Ueyama auto existingEvent = dyn_cast<EventSymbol>(existing); 175136d27abSRui Ueyama if (!isa<EventSymbol>(existing)) { 176136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT); 177e915a71fSHeejin Ahn return; 178e915a71fSHeejin Ahn } 179e915a71fSHeejin Ahn 180136d27abSRui Ueyama const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType(); 181136d27abSRui Ueyama const WasmSignature *oldSig = existingEvent->signature; 182136d27abSRui Ueyama if (newType->Attribute != oldType->Attribute) 183136d27abSRui Ueyama error("Event type mismatch: " + existing->getName() + "\n>>> defined as " + 184136d27abSRui Ueyama toString(*oldType) + " in " + toString(existing->getFile()) + 185136d27abSRui Ueyama "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 186136d27abSRui Ueyama if (*newSig != *oldSig) 187136d27abSRui Ueyama warn("Event signature mismatch: " + existing->getName() + 188136d27abSRui Ueyama "\n>>> defined as " + toString(*oldSig) + " in " + 189136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined as " + 190136d27abSRui Ueyama toString(*newSig) + " in " + toString(file)); 191e915a71fSHeejin Ahn } 192e915a71fSHeejin Ahn 19353e3b81fSAndy Wingo static void checkTableType(const Symbol *existing, const InputFile *file, 19453e3b81fSAndy Wingo const WasmTableType *newType) { 19553e3b81fSAndy Wingo if (!isa<TableSymbol>(existing)) { 19653e3b81fSAndy Wingo reportTypeError(existing, file, WASM_SYMBOL_TYPE_TABLE); 19753e3b81fSAndy Wingo return; 19853e3b81fSAndy Wingo } 19953e3b81fSAndy Wingo 20053e3b81fSAndy Wingo const WasmTableType *oldType = cast<TableSymbol>(existing)->getTableType(); 20153e3b81fSAndy Wingo if (newType->ElemType != oldType->ElemType) { 20253e3b81fSAndy Wingo error("Table type mismatch: " + existing->getName() + "\n>>> defined as " + 20353e3b81fSAndy Wingo toString(*oldType) + " in " + toString(existing->getFile()) + 20453e3b81fSAndy Wingo "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 20553e3b81fSAndy Wingo } 20653e3b81fSAndy Wingo // FIXME: No assertions currently on the limits. 20753e3b81fSAndy Wingo } 20853e3b81fSAndy Wingo 209136d27abSRui Ueyama static void checkDataType(const Symbol *existing, const InputFile *file) { 210136d27abSRui Ueyama if (!isa<DataSymbol>(existing)) 211136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA); 212e3498ec5SRui Ueyama } 213e3498ec5SRui Ueyama 214136d27abSRui Ueyama DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, 215136d27abSRui Ueyama uint32_t flags, 216136d27abSRui Ueyama InputFunction *function) { 217136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); 218136d27abSRui Ueyama assert(!find(name)); 219136d27abSRui Ueyama syntheticFunctions.emplace_back(function); 220136d27abSRui Ueyama return replaceSymbol<DefinedFunction>(insertName(name).first, name, 221136d27abSRui Ueyama flags, nullptr, function); 22250686856SSam Clegg } 22350686856SSam Clegg 22429a3056bSSam Clegg // Adds an optional, linker generated, data symbol. The symbol will only be 2257ae3d335SKazuaki Ishizaki // added if there is an undefine reference to it, or if it is explicitly 2267ae3d335SKazuaki Ishizaki // exported via the --export flag. Otherwise we don't add the symbol and return 2277ae3d335SKazuaki Ishizaki // nullptr. 228caa0db13SSam Clegg DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, 229582fd474SWouter van Oortmerssen uint64_t value) { 230136d27abSRui Ueyama Symbol *s = find(name); 231136d27abSRui Ueyama if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0)) 232136d27abSRui Ueyama s = insertName(name).first; 233136d27abSRui Ueyama else if (!s || s->isDefined()) 2344bce63a0SSam Clegg return nullptr; 235136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n"); 236caa0db13SSam Clegg auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN); 23714ffbb84SSam Clegg rtn->setVA(value); 238136d27abSRui Ueyama rtn->referenced = true; 2394bce63a0SSam Clegg return rtn; 2404bce63a0SSam Clegg } 2414bce63a0SSam Clegg 242136d27abSRui Ueyama DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, 243136d27abSRui Ueyama uint32_t flags) { 244136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); 245136d27abSRui Ueyama assert(!find(name)); 246136d27abSRui Ueyama return replaceSymbol<DefinedData>(insertName(name).first, name, flags); 247c94d393aSSam Clegg } 248c94d393aSSam Clegg 249136d27abSRui Ueyama DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, 250136d27abSRui Ueyama InputGlobal *global) { 251136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global 252e7245b42SNicola Zaghen << "\n"); 253136d27abSRui Ueyama assert(!find(name)); 254136d27abSRui Ueyama syntheticGlobals.emplace_back(global); 255136d27abSRui Ueyama return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags, 256136d27abSRui Ueyama nullptr, global); 25793102974SSam Clegg } 25893102974SSam Clegg 25988e4056bSSam Clegg DefinedGlobal *SymbolTable::addOptionalGlobalSymbol(StringRef name, 26029a3056bSSam Clegg InputGlobal *global) { 26188e4056bSSam Clegg LLVM_DEBUG(dbgs() << "addOptionalGlobalSymbol: " << name << " -> " << global 26229a3056bSSam Clegg << "\n"); 26329a3056bSSam Clegg Symbol *s = find(name); 26429a3056bSSam Clegg if (!s || s->isDefined()) 26529a3056bSSam Clegg return nullptr; 26629a3056bSSam Clegg syntheticGlobals.emplace_back(global); 26788e4056bSSam Clegg return replaceSymbol<DefinedGlobal>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN, 26888e4056bSSam Clegg nullptr, global); 26929a3056bSSam Clegg } 27029a3056bSSam Clegg 27163393828SAndy Wingo DefinedTable *SymbolTable::addSyntheticTable(StringRef name, uint32_t flags, 27263393828SAndy Wingo InputTable *table) { 27363393828SAndy Wingo LLVM_DEBUG(dbgs() << "addSyntheticTable: " << name << " -> " << table 27463393828SAndy Wingo << "\n"); 27563393828SAndy Wingo Symbol *s = find(name); 27663393828SAndy Wingo assert(!s || s->isUndefined()); 27763393828SAndy Wingo if (!s) 27863393828SAndy Wingo s = insertName(name).first; 27963393828SAndy Wingo syntheticTables.emplace_back(table); 28063393828SAndy Wingo return replaceSymbol<DefinedTable>(s, name, flags, nullptr, table); 28163393828SAndy Wingo } 28263393828SAndy Wingo 283136d27abSRui Ueyama static bool shouldReplace(const Symbol *existing, InputFile *newFile, 284136d27abSRui Ueyama uint32_t newFlags) { 285c03c9040SRui Ueyama // If existing symbol is undefined, replace it. 286136d27abSRui Ueyama if (!existing->isDefined()) { 287e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 288136d27abSRui Ueyama << existing->getName() << "\n"); 289c03c9040SRui Ueyama return true; 290c03c9040SRui Ueyama } 291c03c9040SRui Ueyama 292c03c9040SRui Ueyama // Now we have two defined symbols. If the new one is weak, we can ignore it. 293136d27abSRui Ueyama if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 294e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 295c03c9040SRui Ueyama return false; 296c03c9040SRui Ueyama } 297c03c9040SRui Ueyama 298c03c9040SRui Ueyama // If the existing symbol is weak, we should replace it. 299136d27abSRui Ueyama if (existing->isWeak()) { 300e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 301c03c9040SRui Ueyama return true; 302c03c9040SRui Ueyama } 303c03c9040SRui Ueyama 304c03c9040SRui Ueyama // Neither symbol is week. They conflict. 305136d27abSRui Ueyama error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + 306136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined in " + 307136d27abSRui Ueyama toString(newFile)); 308c03c9040SRui Ueyama return true; 309b8621596SSam Clegg } 31093e559b1SSam Clegg 311136d27abSRui Ueyama Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags, 312136d27abSRui Ueyama InputFile *file, 313136d27abSRui Ueyama InputFunction *function) { 314136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " [" 315136d27abSRui Ueyama << (function ? toString(function->signature) : "none") 3168b0b48f3SSam Clegg << "]\n"); 317136d27abSRui Ueyama Symbol *s; 318136d27abSRui Ueyama bool wasInserted; 319136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 320c729c1b4SSam Clegg 321136d27abSRui Ueyama auto replaceSym = [&](Symbol *sym) { 3227c5fcb35SKazuaki Ishizaki // If the new defined function doesn't have signature (i.e. bitcode 3236540e570SSam Clegg // functions) but the old symbol does, then preserve the old signature 324136d27abSRui Ueyama const WasmSignature *oldSig = s->getSignature(); 325136d27abSRui Ueyama auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function); 326136d27abSRui Ueyama if (!newSym->signature) 327136d27abSRui Ueyama newSym->signature = oldSig; 3286540e570SSam Clegg }; 3296540e570SSam Clegg 330136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 331136d27abSRui Ueyama replaceSym(s); 332136d27abSRui Ueyama return s; 333e3498ec5SRui Ueyama } 334e3498ec5SRui Ueyama 335136d27abSRui Ueyama auto existingFunction = dyn_cast<FunctionSymbol>(s); 336136d27abSRui Ueyama if (!existingFunction) { 337136d27abSRui Ueyama reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 338136d27abSRui Ueyama return s; 3398b0b48f3SSam Clegg } 3406540e570SSam Clegg 341136d27abSRui Ueyama bool checkSig = true; 342136d27abSRui Ueyama if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) 343136d27abSRui Ueyama checkSig = ud->isCalledDirectly; 34459f959ffSSam Clegg 345136d27abSRui Ueyama if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) { 346136d27abSRui Ueyama Symbol* variant; 347136d27abSRui Ueyama if (getFunctionVariant(s, &function->signature, file, &variant)) 3486540e570SSam Clegg // New variant, always replace 349136d27abSRui Ueyama replaceSym(variant); 350136d27abSRui Ueyama else if (shouldReplace(s, file, flags)) 3516540e570SSam Clegg // Variant already exists, replace it after checking shouldReplace 352136d27abSRui Ueyama replaceSym(variant); 3536540e570SSam Clegg 3546540e570SSam Clegg // This variant we found take the place in the symbol table as the primary 3556540e570SSam Clegg // variant. 356136d27abSRui Ueyama replace(name, variant); 357136d27abSRui Ueyama return variant; 3586540e570SSam Clegg } 3596540e570SSam Clegg 3606540e570SSam Clegg // Existing function with matching signature. 361136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 362136d27abSRui Ueyama replaceSym(s); 3636540e570SSam Clegg 364136d27abSRui Ueyama return s; 36593e559b1SSam Clegg } 36693e559b1SSam Clegg 367136d27abSRui Ueyama Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, 368136d27abSRui Ueyama InputFile *file, InputSegment *segment, 3693b29376eSWouter van Oortmerssen uint64_t address, uint64_t size) { 370136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address 371e7245b42SNicola Zaghen << "\n"); 372136d27abSRui Ueyama Symbol *s; 373136d27abSRui Ueyama bool wasInserted; 374136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 375c729c1b4SSam Clegg 376136d27abSRui Ueyama auto replaceSym = [&]() { 377136d27abSRui Ueyama replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size); 3786540e570SSam Clegg }; 3796540e570SSam Clegg 380136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 381136d27abSRui Ueyama replaceSym(); 382136d27abSRui Ueyama return s; 383e3498ec5SRui Ueyama } 384e3498ec5SRui Ueyama 385136d27abSRui Ueyama checkDataType(s, file); 386e3498ec5SRui Ueyama 387136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 388136d27abSRui Ueyama replaceSym(); 389136d27abSRui Ueyama return s; 390c94d393aSSam Clegg } 391c94d393aSSam Clegg 392136d27abSRui Ueyama Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags, 393136d27abSRui Ueyama InputFile *file, InputGlobal *global) { 394136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n"); 3954c2cbfe6SSam Clegg 396136d27abSRui Ueyama Symbol *s; 397136d27abSRui Ueyama bool wasInserted; 398136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 399c729c1b4SSam Clegg 400136d27abSRui Ueyama auto replaceSym = [&]() { 401136d27abSRui Ueyama replaceSymbol<DefinedGlobal>(s, name, flags, file, global); 4026540e570SSam Clegg }; 4036540e570SSam Clegg 404136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 405136d27abSRui Ueyama replaceSym(); 406136d27abSRui Ueyama return s; 40793102974SSam Clegg } 40893102974SSam Clegg 409136d27abSRui Ueyama checkGlobalType(s, file, &global->getType()); 410e3498ec5SRui Ueyama 411136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 412136d27abSRui Ueyama replaceSym(); 413136d27abSRui Ueyama return s; 414e3498ec5SRui Ueyama } 415e3498ec5SRui Ueyama 416136d27abSRui Ueyama Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags, 417136d27abSRui Ueyama InputFile *file, InputEvent *event) { 418136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n"); 419e915a71fSHeejin Ahn 420136d27abSRui Ueyama Symbol *s; 421136d27abSRui Ueyama bool wasInserted; 422136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 423e915a71fSHeejin Ahn 424136d27abSRui Ueyama auto replaceSym = [&]() { 425136d27abSRui Ueyama replaceSymbol<DefinedEvent>(s, name, flags, file, event); 4266540e570SSam Clegg }; 4276540e570SSam Clegg 428136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 429136d27abSRui Ueyama replaceSym(); 430136d27abSRui Ueyama return s; 431e915a71fSHeejin Ahn } 432e915a71fSHeejin Ahn 433136d27abSRui Ueyama checkEventType(s, file, &event->getType(), &event->signature); 434e915a71fSHeejin Ahn 435136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 436136d27abSRui Ueyama replaceSym(); 437136d27abSRui Ueyama return s; 438e915a71fSHeejin Ahn } 439e915a71fSHeejin Ahn 44053e3b81fSAndy Wingo Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags, 44153e3b81fSAndy Wingo InputFile *file, InputTable *table) { 44253e3b81fSAndy Wingo LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n"); 44353e3b81fSAndy Wingo 44453e3b81fSAndy Wingo Symbol *s; 44553e3b81fSAndy Wingo bool wasInserted; 44653e3b81fSAndy Wingo std::tie(s, wasInserted) = insert(name, file); 44753e3b81fSAndy Wingo 44853e3b81fSAndy Wingo auto replaceSym = [&]() { 44953e3b81fSAndy Wingo replaceSymbol<DefinedTable>(s, name, flags, file, table); 45053e3b81fSAndy Wingo }; 45153e3b81fSAndy Wingo 45253e3b81fSAndy Wingo if (wasInserted || s->isLazy()) { 45353e3b81fSAndy Wingo replaceSym(); 45453e3b81fSAndy Wingo return s; 45553e3b81fSAndy Wingo } 45653e3b81fSAndy Wingo 45753e3b81fSAndy Wingo checkTableType(s, file, &table->getType()); 45853e3b81fSAndy Wingo 45953e3b81fSAndy Wingo if (shouldReplace(s, file, flags)) 46053e3b81fSAndy Wingo replaceSym(); 46153e3b81fSAndy Wingo return s; 46253e3b81fSAndy Wingo } 46353e3b81fSAndy Wingo 46467b05584SSam Clegg // This function get called when an undefined symbol is added, and there is 46567b05584SSam Clegg // already an existing one in the symbols table. In this case we check that 46667b05584SSam Clegg // custom 'import-module' and 'import-field' symbol attributes agree. 4677ae3d335SKazuaki Ishizaki // With LTO these attributes are not available when the bitcode is read and only 46867b05584SSam Clegg // become available when the LTO object is read. In this case we silently 46967b05584SSam Clegg // replace the empty attributes with the valid ones. 47067b05584SSam Clegg template <typename T> 471bd481277SSam Clegg static void setImportAttributes(T *existing, Optional<StringRef> importName, 472bd481277SSam Clegg Optional<StringRef> importModule, 473a57f1a54SSam Clegg uint32_t flags, InputFile *file) { 474bd481277SSam Clegg if (importName) { 475bd481277SSam Clegg if (!existing->importName) 47667b05584SSam Clegg existing->importName = importName; 47767b05584SSam Clegg if (existing->importName != importName) 47867b05584SSam Clegg error("import name mismatch for symbol: " + toString(*existing) + 479bd481277SSam Clegg "\n>>> defined as " + *existing->importName + " in " + 480bd481277SSam Clegg toString(existing->getFile()) + "\n>>> defined as " + *importName + 48167b05584SSam Clegg " in " + toString(file)); 48267b05584SSam Clegg } 48367b05584SSam Clegg 484bd481277SSam Clegg if (importModule) { 485bd481277SSam Clegg if (!existing->importModule) 48667b05584SSam Clegg existing->importModule = importModule; 48767b05584SSam Clegg if (existing->importModule != importModule) 48867b05584SSam Clegg error("import module mismatch for symbol: " + toString(*existing) + 489bd481277SSam Clegg "\n>>> defined as " + *existing->importModule + " in " + 490bd481277SSam Clegg toString(existing->getFile()) + "\n>>> defined as " + 491bd481277SSam Clegg *importModule + " in " + toString(file)); 49267b05584SSam Clegg } 493a57f1a54SSam Clegg 494a57f1a54SSam Clegg // Update symbol binding, if the existing symbol is weak 495a57f1a54SSam Clegg uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK; 496a57f1a54SSam Clegg if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) { 497a57f1a54SSam Clegg existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding; 498a57f1a54SSam Clegg } 49967b05584SSam Clegg } 50067b05584SSam Clegg 501bd481277SSam Clegg Symbol *SymbolTable::addUndefinedFunction(StringRef name, 502bd481277SSam Clegg Optional<StringRef> importName, 503bd481277SSam Clegg Optional<StringRef> importModule, 504136d27abSRui Ueyama uint32_t flags, InputFile *file, 505136d27abSRui Ueyama const WasmSignature *sig, 506136d27abSRui Ueyama bool isCalledDirectly) { 507136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" 508136d27abSRui Ueyama << (sig ? toString(*sig) : "none") 509a57f1a54SSam Clegg << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x" 510a57f1a54SSam Clegg << utohexstr(flags) << "\n"); 511f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 512c03c9040SRui Ueyama 513136d27abSRui Ueyama Symbol *s; 514136d27abSRui Ueyama bool wasInserted; 515136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 516136d27abSRui Ueyama if (s->traced) 517136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 518c729c1b4SSam Clegg 519136d27abSRui Ueyama auto replaceSym = [&]() { 520136d27abSRui Ueyama replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags, 521136d27abSRui Ueyama file, sig, isCalledDirectly); 5226540e570SSam Clegg }; 5236540e570SSam Clegg 524b34ec596SSam Clegg if (wasInserted) { 525136d27abSRui Ueyama replaceSym(); 526b34ec596SSam Clegg } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 527b34ec596SSam Clegg if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 528b34ec596SSam Clegg lazy->setWeak(); 529b34ec596SSam Clegg lazy->signature = sig; 530b34ec596SSam Clegg } else { 531136d27abSRui Ueyama lazy->fetch(); 532b34ec596SSam Clegg } 533b34ec596SSam Clegg } else { 534136d27abSRui Ueyama auto existingFunction = dyn_cast<FunctionSymbol>(s); 535136d27abSRui Ueyama if (!existingFunction) { 536136d27abSRui Ueyama reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 537136d27abSRui Ueyama return s; 5386540e570SSam Clegg } 539136d27abSRui Ueyama if (!existingFunction->signature && sig) 540136d27abSRui Ueyama existingFunction->signature = sig; 541a57f1a54SSam Clegg auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction); 542fecfc592SSam Clegg if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { 543a57f1a54SSam Clegg // If the existing undefined functions is not called directly then let 544fecfc592SSam Clegg // this one take precedence. Otherwise the existing function is either 545a57f1a54SSam Clegg // directly called or defined, in which case we need a function variant. 546fecfc592SSam Clegg if (existingUndefined && !existingUndefined->isCalledDirectly) 547136d27abSRui Ueyama replaceSym(); 548fecfc592SSam Clegg else if (getFunctionVariant(s, sig, file, &s)) 549fecfc592SSam Clegg replaceSym(); 550fecfc592SSam Clegg } 55167b05584SSam Clegg if (existingUndefined) 552a57f1a54SSam Clegg setImportAttributes(existingUndefined, importName, importModule, flags, 553a57f1a54SSam Clegg file); 5546540e570SSam Clegg } 555cefbf9acSSam Clegg 556136d27abSRui Ueyama return s; 557c03c9040SRui Ueyama } 558c03c9040SRui Ueyama 559136d27abSRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, 560136d27abSRui Ueyama InputFile *file) { 561136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); 562f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 56393102974SSam Clegg 564136d27abSRui Ueyama Symbol *s; 565136d27abSRui Ueyama bool wasInserted; 566136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 567136d27abSRui Ueyama if (s->traced) 568136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 569f989a92dSSam Clegg 570b34ec596SSam Clegg if (wasInserted) { 571136d27abSRui Ueyama replaceSymbol<UndefinedData>(s, name, flags, file); 572b34ec596SSam Clegg } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 573b34ec596SSam Clegg if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) 574b34ec596SSam Clegg lazy->setWeak(); 575b34ec596SSam Clegg else 576136d27abSRui Ueyama lazy->fetch(); 577b34ec596SSam Clegg } else if (s->isDefined()) { 578136d27abSRui Ueyama checkDataType(s, file); 579b34ec596SSam Clegg } 580136d27abSRui Ueyama return s; 581c94d393aSSam Clegg } 582c94d393aSSam Clegg 583bd481277SSam Clegg Symbol *SymbolTable::addUndefinedGlobal(StringRef name, 584bd481277SSam Clegg Optional<StringRef> importName, 585bd481277SSam Clegg Optional<StringRef> importModule, 586bd481277SSam Clegg uint32_t flags, InputFile *file, 587136d27abSRui Ueyama const WasmGlobalType *type) { 588136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); 589f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 590e3498ec5SRui Ueyama 591136d27abSRui Ueyama Symbol *s; 592136d27abSRui Ueyama bool wasInserted; 593136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 594136d27abSRui Ueyama if (s->traced) 595136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 596c729c1b4SSam Clegg 597136d27abSRui Ueyama if (wasInserted) 598136d27abSRui Ueyama replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, 599136d27abSRui Ueyama file, type); 600136d27abSRui Ueyama else if (auto *lazy = dyn_cast<LazySymbol>(s)) 601136d27abSRui Ueyama lazy->fetch(); 602136d27abSRui Ueyama else if (s->isDefined()) 603136d27abSRui Ueyama checkGlobalType(s, file, type); 604136d27abSRui Ueyama return s; 605e3498ec5SRui Ueyama } 606e3498ec5SRui Ueyama 60753e3b81fSAndy Wingo Symbol *SymbolTable::addUndefinedTable(StringRef name, 60853e3b81fSAndy Wingo Optional<StringRef> importName, 60953e3b81fSAndy Wingo Optional<StringRef> importModule, 61053e3b81fSAndy Wingo uint32_t flags, InputFile *file, 61153e3b81fSAndy Wingo const WasmTableType *type) { 61253e3b81fSAndy Wingo LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n"); 61353e3b81fSAndy Wingo assert(flags & WASM_SYMBOL_UNDEFINED); 61453e3b81fSAndy Wingo 61553e3b81fSAndy Wingo Symbol *s; 61653e3b81fSAndy Wingo bool wasInserted; 61753e3b81fSAndy Wingo std::tie(s, wasInserted) = insert(name, file); 61853e3b81fSAndy Wingo if (s->traced) 61953e3b81fSAndy Wingo printTraceSymbolUndefined(name, file); 62053e3b81fSAndy Wingo 62153e3b81fSAndy Wingo if (wasInserted) 62253e3b81fSAndy Wingo replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags, 62353e3b81fSAndy Wingo file, type); 62453e3b81fSAndy Wingo else if (auto *lazy = dyn_cast<LazySymbol>(s)) 62553e3b81fSAndy Wingo lazy->fetch(); 62653e3b81fSAndy Wingo else if (s->isDefined()) 62753e3b81fSAndy Wingo checkTableType(s, file, type); 62853e3b81fSAndy Wingo return s; 62953e3b81fSAndy Wingo } 63053e3b81fSAndy Wingo 631*e638d8b2SAndy Wingo TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) { 632*e638d8b2SAndy Wingo WasmLimits limits{0, 0, 0}; // Set by the writer. 633*e638d8b2SAndy Wingo WasmTableType *type = make<WasmTableType>(); 634*e638d8b2SAndy Wingo type->ElemType = uint8_t(ValType::FUNCREF); 635*e638d8b2SAndy Wingo type->Limits = limits; 636*e638d8b2SAndy Wingo StringRef module(defaultModule); 637*e638d8b2SAndy Wingo uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; 638*e638d8b2SAndy Wingo flags |= WASM_SYMBOL_UNDEFINED; 639*e638d8b2SAndy Wingo Symbol *sym = addUndefinedTable(name, name, module, flags, nullptr, type); 640*e638d8b2SAndy Wingo sym->markLive(); 641*e638d8b2SAndy Wingo sym->forceExport = config->exportTable; 642*e638d8b2SAndy Wingo return cast<TableSymbol>(sym); 643*e638d8b2SAndy Wingo } 644*e638d8b2SAndy Wingo 645*e638d8b2SAndy Wingo TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) { 646*e638d8b2SAndy Wingo const uint32_t invalidIndex = -1; 647*e638d8b2SAndy Wingo WasmLimits limits{0, 0, 0}; // Set by the writer. 648*e638d8b2SAndy Wingo WasmTableType type{uint8_t(ValType::FUNCREF), limits}; 649*e638d8b2SAndy Wingo WasmTable desc{invalidIndex, type, name}; 650*e638d8b2SAndy Wingo InputTable *table = make<InputTable>(desc, nullptr); 651*e638d8b2SAndy Wingo uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; 652*e638d8b2SAndy Wingo TableSymbol *sym = addSyntheticTable(name, flags, table); 653*e638d8b2SAndy Wingo sym->markLive(); 654*e638d8b2SAndy Wingo sym->forceExport = config->exportTable; 655*e638d8b2SAndy Wingo return sym; 656*e638d8b2SAndy Wingo } 657*e638d8b2SAndy Wingo 658*e638d8b2SAndy Wingo // Whether or not we need an indirect function table is usually a function of 659*e638d8b2SAndy Wingo // whether an input declares a need for it. However sometimes it's possible for 660*e638d8b2SAndy Wingo // no input to need the indirect function table, but then a late 661*e638d8b2SAndy Wingo // addInternalGOTEntry causes a function to be allocated an address. In that 662*e638d8b2SAndy Wingo // case address we synthesize a definition at the last minute. 663*e638d8b2SAndy Wingo TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) { 664*e638d8b2SAndy Wingo Symbol *existing = find(functionTableName); 665*e638d8b2SAndy Wingo if (existing) { 666*e638d8b2SAndy Wingo if (!isa<TableSymbol>(existing)) { 667*e638d8b2SAndy Wingo error(Twine("reserved symbol must be of type table: `") + 668*e638d8b2SAndy Wingo functionTableName + "`"); 669*e638d8b2SAndy Wingo return nullptr; 670*e638d8b2SAndy Wingo } 671*e638d8b2SAndy Wingo if (existing->isDefined()) { 672*e638d8b2SAndy Wingo error(Twine("reserved symbol must not be defined in input files: `") + 673*e638d8b2SAndy Wingo functionTableName + "`"); 674*e638d8b2SAndy Wingo return nullptr; 675*e638d8b2SAndy Wingo } 676*e638d8b2SAndy Wingo } 677*e638d8b2SAndy Wingo 678*e638d8b2SAndy Wingo if (config->importTable) { 679*e638d8b2SAndy Wingo if (existing) 680*e638d8b2SAndy Wingo return cast<TableSymbol>(existing); 681*e638d8b2SAndy Wingo if (required) 682*e638d8b2SAndy Wingo return createUndefinedIndirectFunctionTable(functionTableName); 683*e638d8b2SAndy Wingo } else if ((existing && existing->isLive()) || config->exportTable || 684*e638d8b2SAndy Wingo required) { 685*e638d8b2SAndy Wingo // A defined table is required. Either because the user request an exported 686*e638d8b2SAndy Wingo // table or because the table symbol is already live. The existing table is 687*e638d8b2SAndy Wingo // guaranteed to be undefined due to the check above. 688*e638d8b2SAndy Wingo return createDefinedIndirectFunctionTable(functionTableName); 689*e638d8b2SAndy Wingo } 690*e638d8b2SAndy Wingo 691*e638d8b2SAndy Wingo // An indirect function table will only be present in the symbol table if 692*e638d8b2SAndy Wingo // needed by a reloc; if we get here, we don't need one. 693*e638d8b2SAndy Wingo return nullptr; 694*e638d8b2SAndy Wingo } 695*e638d8b2SAndy Wingo 696136d27abSRui Ueyama void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) { 697136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n"); 698136d27abSRui Ueyama StringRef name = sym->getName(); 699c03c9040SRui Ueyama 700136d27abSRui Ueyama Symbol *s; 701136d27abSRui Ueyama bool wasInserted; 702136d27abSRui Ueyama std::tie(s, wasInserted) = insertName(name); 703c03c9040SRui Ueyama 704136d27abSRui Ueyama if (wasInserted) { 705136d27abSRui Ueyama replaceSymbol<LazySymbol>(s, name, 0, file, *sym); 706c03c9040SRui Ueyama return; 707c03c9040SRui Ueyama } 708c03c9040SRui Ueyama 709136d27abSRui Ueyama if (!s->isUndefined()) 71037b4ee52SSam Clegg return; 71137b4ee52SSam Clegg 71237b4ee52SSam Clegg // The existing symbol is undefined, load a new one from the archive, 7137ae3d335SKazuaki Ishizaki // unless the existing symbol is weak in which case replace the undefined 71437b4ee52SSam Clegg // symbols with a LazySymbol. 715136d27abSRui Ueyama if (s->isWeak()) { 716136d27abSRui Ueyama const WasmSignature *oldSig = nullptr; 71737b4ee52SSam Clegg // In the case of an UndefinedFunction we need to preserve the expected 71837b4ee52SSam Clegg // signature. 719136d27abSRui Ueyama if (auto *f = dyn_cast<UndefinedFunction>(s)) 720136d27abSRui Ueyama oldSig = f->signature; 72137b4ee52SSam Clegg LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 722136d27abSRui Ueyama auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, 723136d27abSRui Ueyama file, *sym); 724136d27abSRui Ueyama newSym->signature = oldSig; 72537b4ee52SSam Clegg return; 72637b4ee52SSam Clegg } 72737b4ee52SSam Clegg 728e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 729136d27abSRui Ueyama file->addMember(sym); 730c94d393aSSam Clegg } 731e0f6fcd0SSam Clegg 732136d27abSRui Ueyama bool SymbolTable::addComdat(StringRef name) { 733136d27abSRui Ueyama return comdatGroups.insert(CachedHashStringRef(name)).second; 734e0f6fcd0SSam Clegg } 7351f3f774fSSam Clegg 7366540e570SSam Clegg // The new signature doesn't match. Create a variant to the symbol with the 7376540e570SSam Clegg // signature encoded in the name and return that instead. These symbols are 7386540e570SSam Clegg // then unified later in handleSymbolVariants. 739136d27abSRui Ueyama bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, 740136d27abSRui Ueyama const InputFile *file, Symbol **out) { 741136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " 742136d27abSRui Ueyama << " " << toString(*sig) << "\n"); 743136d27abSRui Ueyama Symbol *variant = nullptr; 7446540e570SSam Clegg 7456540e570SSam Clegg // Linear search through symbol variants. Should never be more than two 7466540e570SSam Clegg // or three entries here. 747136d27abSRui Ueyama auto &variants = symVariants[CachedHashStringRef(sym->getName())]; 748136d27abSRui Ueyama if (variants.empty()) 749136d27abSRui Ueyama variants.push_back(sym); 7506540e570SSam Clegg 751136d27abSRui Ueyama for (Symbol* v : variants) { 752136d27abSRui Ueyama if (*v->getSignature() == *sig) { 753136d27abSRui Ueyama variant = v; 7546540e570SSam Clegg break; 7556540e570SSam Clegg } 7566540e570SSam Clegg } 7576540e570SSam Clegg 758136d27abSRui Ueyama bool wasAdded = !variant; 759136d27abSRui Ueyama if (wasAdded) { 7606540e570SSam Clegg // Create a new variant; 7616540e570SSam Clegg LLVM_DEBUG(dbgs() << "added new variant\n"); 762136d27abSRui Ueyama variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 763064e9907SSam Clegg variant->isUsedInRegularObj = 764064e9907SSam Clegg !file || file->kind() == InputFile::ObjectKind; 765064e9907SSam Clegg variant->canInline = true; 766064e9907SSam Clegg variant->traced = false; 767064e9907SSam Clegg variant->forceExport = false; 768136d27abSRui Ueyama variants.push_back(variant); 7696540e570SSam Clegg } else { 770136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); 771136d27abSRui Ueyama assert(*variant->getSignature() == *sig); 7726540e570SSam Clegg } 7736540e570SSam Clegg 774136d27abSRui Ueyama *out = variant; 775136d27abSRui Ueyama return wasAdded; 7766540e570SSam Clegg } 7776540e570SSam Clegg 7781f3f774fSSam Clegg // Set a flag for --trace-symbol so that we can print out a log message 7791f3f774fSSam Clegg // if a new symbol with the same name is inserted into the symbol table. 780136d27abSRui Ueyama void SymbolTable::trace(StringRef name) { 781136d27abSRui Ueyama symMap.insert({CachedHashStringRef(name), -1}); 7821f3f774fSSam Clegg } 783230dc11dSSam Clegg 784136d27abSRui Ueyama void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { 785a5ca34e6SSam Clegg // Swap symbols as instructed by -wrap. 786136d27abSRui Ueyama int &origIdx = symMap[CachedHashStringRef(sym->getName())]; 787136d27abSRui Ueyama int &realIdx= symMap[CachedHashStringRef(real->getName())]; 788136d27abSRui Ueyama int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; 789136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); 790a5ca34e6SSam Clegg 791a5ca34e6SSam Clegg // Anyone looking up __real symbols should get the original 792136d27abSRui Ueyama realIdx = origIdx; 793a5ca34e6SSam Clegg // Anyone looking up the original should get the __wrap symbol 794136d27abSRui Ueyama origIdx = wrapIdx; 795a5ca34e6SSam Clegg } 796a5ca34e6SSam Clegg 797136d27abSRui Ueyama static const uint8_t unreachableFn[] = { 798230dc11dSSam Clegg 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 799230dc11dSSam Clegg 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 800230dc11dSSam Clegg }; 801230dc11dSSam Clegg 802230dc11dSSam Clegg // Replace the given symbol body with an unreachable function. 803230dc11dSSam Clegg // This is used by handleWeakUndefines in order to generate a callable 8046540e570SSam Clegg // equivalent of an undefined function and also handleSymbolVariants for 8056540e570SSam Clegg // undefined functions that don't match the signature of the definition. 806136d27abSRui Ueyama InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, 807136d27abSRui Ueyama const WasmSignature &sig, 808136d27abSRui Ueyama StringRef debugName) { 809136d27abSRui Ueyama auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); 810136d27abSRui Ueyama func->setBody(unreachableFn); 811136d27abSRui Ueyama syntheticFunctions.emplace_back(func); 8124b8e2d8eSSam Clegg // Mark new symbols as local. For relocatable output we don't want them 8134b8e2d8eSSam Clegg // to be exported outside the object file. 8144b8e2d8eSSam Clegg replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL, 8154b8e2d8eSSam Clegg nullptr, func); 81648ddf5e1SSam Clegg // Ensure the stub function doesn't get a table entry. Its address 81748ddf5e1SSam Clegg // should always compare equal to the null pointer. 81848ddf5e1SSam Clegg sym->isStub = true; 819136d27abSRui Ueyama return func; 820230dc11dSSam Clegg } 821230dc11dSSam Clegg 822206884bfSSam Clegg void SymbolTable::replaceWithUndefined(Symbol *sym) { 823206884bfSSam Clegg // Add a synthetic dummy for weak undefined functions. These dummies will 824206884bfSSam Clegg // be GC'd if not used as the target of any "call" instructions. 825206884bfSSam Clegg StringRef debugName = saver.save("undefined_weak:" + toString(*sym)); 826206884bfSSam Clegg replaceWithUnreachable(sym, *sym->getSignature(), debugName); 827206884bfSSam Clegg // Hide our dummy to prevent export. 828206884bfSSam Clegg sym->setHidden(true); 829206884bfSSam Clegg } 830206884bfSSam Clegg 831230dc11dSSam Clegg // For weak undefined functions, there may be "call" instructions that reference 832230dc11dSSam Clegg // the symbol. In this case, we need to synthesise a dummy/stub function that 833230dc11dSSam Clegg // will abort at runtime, so that relocations can still provided an operand to 834230dc11dSSam Clegg // the call instruction that passes Wasm validation. 835230dc11dSSam Clegg void SymbolTable::handleWeakUndefines() { 836136d27abSRui Ueyama for (Symbol *sym : getSymbols()) { 837206884bfSSam Clegg if (sym->isUndefWeak()) { 838206884bfSSam Clegg if (sym->getSignature()) { 839206884bfSSam Clegg replaceWithUndefined(sym); 840206884bfSSam Clegg } else { 841206884bfSSam Clegg // It is possible for undefined functions not to have a signature (eg. 842206884bfSSam Clegg // if added via "--undefined"), but weak undefined ones do have a 843206884bfSSam Clegg // signature. Lazy symbols may not be functions and therefore Sig can 844206884bfSSam Clegg // still be null in some circumstance. 845136d27abSRui Ueyama assert(!isa<FunctionSymbol>(sym)); 846206884bfSSam Clegg } 847206884bfSSam Clegg } 848206884bfSSam Clegg } 8496540e570SSam Clegg } 850230dc11dSSam Clegg 851206884bfSSam Clegg DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) { 852206884bfSSam Clegg if (stubFunctions.count(sig)) 853206884bfSSam Clegg return stubFunctions[sig]; 854206884bfSSam Clegg LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n"); 855206884bfSSam Clegg auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>()); 856206884bfSSam Clegg sym->isUsedInRegularObj = true; 857206884bfSSam Clegg sym->canInline = true; 858206884bfSSam Clegg sym->traced = false; 859206884bfSSam Clegg sym->forceExport = false; 860206884bfSSam Clegg sym->signature = &sig; 861206884bfSSam Clegg replaceSymbol<DefinedFunction>( 862206884bfSSam Clegg sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr); 863206884bfSSam Clegg replaceWithUnreachable(sym, sig, "undefined_stub"); 864206884bfSSam Clegg stubFunctions[sig] = sym; 865206884bfSSam Clegg return sym; 866230dc11dSSam Clegg } 8676540e570SSam Clegg 868136d27abSRui Ueyama static void reportFunctionSignatureMismatch(StringRef symName, 869136d27abSRui Ueyama FunctionSymbol *a, 870136d27abSRui Ueyama FunctionSymbol *b, bool isError) { 871136d27abSRui Ueyama std::string msg = ("function signature mismatch: " + symName + 872136d27abSRui Ueyama "\n>>> defined as " + toString(*a->signature) + " in " + 873136d27abSRui Ueyama toString(a->getFile()) + "\n>>> defined as " + 874136d27abSRui Ueyama toString(*b->signature) + " in " + toString(b->getFile())) 8756540e570SSam Clegg .str(); 876136d27abSRui Ueyama if (isError) 8776540e570SSam Clegg error(msg); 8786540e570SSam Clegg else 8796540e570SSam Clegg warn(msg); 8806540e570SSam Clegg } 8816540e570SSam Clegg 8826540e570SSam Clegg // Remove any variant symbols that were created due to function signature 8836540e570SSam Clegg // mismatches. 8846540e570SSam Clegg void SymbolTable::handleSymbolVariants() { 885136d27abSRui Ueyama for (auto pair : symVariants) { 8866540e570SSam Clegg // Push the initial symbol onto the list of variants. 887136d27abSRui Ueyama StringRef symName = pair.first.val(); 888136d27abSRui Ueyama std::vector<Symbol *> &variants = pair.second; 8896540e570SSam Clegg 8906540e570SSam Clegg #ifndef NDEBUG 891136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() 892136d27abSRui Ueyama << ") variants: " << symName << "\n"); 893136d27abSRui Ueyama for (auto *s: variants) { 894136d27abSRui Ueyama auto *f = cast<FunctionSymbol>(s); 895136d27abSRui Ueyama LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " 896136d27abSRui Ueyama << toString(*f->signature) << "\n"); 8976540e570SSam Clegg } 8986540e570SSam Clegg #endif 8996540e570SSam Clegg 9006540e570SSam Clegg // Find the one definition. 901136d27abSRui Ueyama DefinedFunction *defined = nullptr; 902136d27abSRui Ueyama for (auto *symbol : variants) { 903136d27abSRui Ueyama if (auto f = dyn_cast<DefinedFunction>(symbol)) { 904136d27abSRui Ueyama defined = f; 9056540e570SSam Clegg break; 9066540e570SSam Clegg } 9076540e570SSam Clegg } 9086540e570SSam Clegg 9096540e570SSam Clegg // If there are no definitions, and the undefined symbols disagree on 9106540e570SSam Clegg // the signature, there is not we can do since we don't know which one 9116540e570SSam Clegg // to use as the signature on the import. 912136d27abSRui Ueyama if (!defined) { 913136d27abSRui Ueyama reportFunctionSignatureMismatch(symName, 914136d27abSRui Ueyama cast<FunctionSymbol>(variants[0]), 915136d27abSRui Ueyama cast<FunctionSymbol>(variants[1]), true); 9166540e570SSam Clegg return; 9176540e570SSam Clegg } 9186540e570SSam Clegg 919136d27abSRui Ueyama for (auto *symbol : variants) { 920136d27abSRui Ueyama if (symbol != defined) { 921136d27abSRui Ueyama auto *f = cast<FunctionSymbol>(symbol); 922136d27abSRui Ueyama reportFunctionSignatureMismatch(symName, f, defined, false); 92351b521c0SSam Clegg StringRef debugName = saver.save("signature_mismatch:" + toString(*f)); 924136d27abSRui Ueyama replaceWithUnreachable(f, *f->signature, debugName); 9256540e570SSam Clegg } 9266540e570SSam Clegg } 9276540e570SSam Clegg } 9286540e570SSam Clegg } 92933c59abfSFangrui Song 93033c59abfSFangrui Song } // namespace wasm 93133c59abfSFangrui Song } // namespace lld 932