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" 1483d59e05SAlexandre Ganea #include "lld/Common/CommonLinkerContext.h" 15b9ef5648SKazu Hirata #include <optional> 16c94d393aSSam Clegg 17c94d393aSSam Clegg #define DEBUG_TYPE "lld" 18c94d393aSSam Clegg 19c94d393aSSam Clegg using namespace llvm; 2020db381bSSam Clegg using namespace llvm::wasm; 2145218f4aSSam Clegg using namespace llvm::object; 22c94d393aSSam Clegg 23d32f71a9SSam Clegg namespace lld::wasm { 2433c59abfSFangrui Song SymbolTable *symtab; 25c94d393aSSam Clegg 267bac0bc1SSam Clegg void SymbolTable::addFile(InputFile *file, StringRef symName) { 27136d27abSRui Ueyama log("Processing: " + toString(file)); 28a282a61bSSam Clegg 29bcc9b9d8SSam Clegg // Lazy object file 30bcc9b9d8SSam Clegg if (file->lazy) { 31bcc9b9d8SSam Clegg if (auto *f = dyn_cast<BitcodeFile>(file)) { 329a450a00SSam Clegg ctx.lazyBitcodeFiles.push_back(f); 33bcc9b9d8SSam Clegg f->parseLazy(); 34bcc9b9d8SSam Clegg } else { 35bcc9b9d8SSam Clegg cast<ObjFile>(file)->parseLazy(); 36bcc9b9d8SSam Clegg } 37a282a61bSSam Clegg return; 38a282a61bSSam Clegg } 39a282a61bSSam Clegg 40a282a61bSSam Clegg // .so file 41136d27abSRui Ueyama if (auto *f = dyn_cast<SharedFile>(file)) { 4222b7b848SSam Clegg // If we are not reporting undefined symbols that we don't actualy 4322b7b848SSam Clegg // parse the shared library symbol table. 4422b7b848SSam Clegg f->parse(); 453c584570SSam Clegg ctx.sharedFiles.push_back(f); 46a282a61bSSam Clegg return; 47a282a61bSSam Clegg } 48a282a61bSSam Clegg 493111784fSSam Clegg // stub file 503111784fSSam Clegg if (auto *f = dyn_cast<StubFile>(file)) { 513111784fSSam Clegg f->parse(); 523c584570SSam Clegg ctx.stubFiles.push_back(f); 533111784fSSam Clegg return; 543111784fSSam Clegg } 553111784fSSam Clegg 563792b362SFangrui Song if (ctx.arg.trace) 57136d27abSRui Ueyama message(toString(file)); 58c94d393aSSam Clegg 59c729c1b4SSam Clegg // LLVM bitcode file 60136d27abSRui Ueyama if (auto *f = dyn_cast<BitcodeFile>(file)) { 6183305faeSHeejin Ahn // This order, first adding to `bitcodeFiles` and then parsing is necessary. 6283305faeSHeejin Ahn // See https://github.com/llvm/llvm-project/pull/73095 633c584570SSam Clegg ctx.bitcodeFiles.push_back(f); 6483305faeSHeejin Ahn f->parse(symName); 65a282a61bSSam Clegg return; 66a282a61bSSam Clegg } 67a282a61bSSam Clegg 68a282a61bSSam Clegg // Regular object file 69136d27abSRui Ueyama auto *f = cast<ObjFile>(file); 70136d27abSRui Ueyama f->parse(false); 713c584570SSam Clegg ctx.objectFiles.push_back(f); 72c94d393aSSam Clegg } 73c94d393aSSam Clegg 74c729c1b4SSam Clegg // This function is where all the optimizations of link-time 75c729c1b4SSam Clegg // optimization happens. When LTO is in use, some input files are 76c729c1b4SSam Clegg // not in native object file format but in the LLVM bitcode format. 77c729c1b4SSam Clegg // This function compiles bitcode files into a few big native files 78c729c1b4SSam Clegg // using LLVM functions and replaces bitcode symbols with the results. 79c729c1b4SSam Clegg // Because all bitcode files that the program consists of are passed 80c729c1b4SSam Clegg // to the compiler at once, it can do whole-program optimization. 814da38c14SSam Clegg void SymbolTable::compileBitcodeFiles() { 82b062fe18SSam Clegg // Prevent further LTO objects being included 83b062fe18SSam Clegg BitcodeFile::doneLTO = true; 84b062fe18SSam Clegg 85c729c1b4SSam Clegg // Compile bitcode files and replace bitcode symbols. 86136d27abSRui Ueyama lto.reset(new BitcodeCompiler); 873c584570SSam Clegg for (BitcodeFile *f : ctx.bitcodeFiles) 88136d27abSRui Ueyama lto->add(*f); 89c729c1b4SSam Clegg 90136d27abSRui Ueyama for (StringRef filename : lto->compile()) { 91136d27abSRui Ueyama auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), ""); 92136d27abSRui Ueyama obj->parse(true); 933c584570SSam Clegg ctx.objectFiles.push_back(obj); 94c729c1b4SSam Clegg } 95c729c1b4SSam Clegg } 96c729c1b4SSam Clegg 97136d27abSRui Ueyama Symbol *SymbolTable::find(StringRef name) { 98136d27abSRui Ueyama auto it = symMap.find(CachedHashStringRef(name)); 99136d27abSRui Ueyama if (it == symMap.end() || it->second == -1) 1001f3f774fSSam Clegg return nullptr; 101136d27abSRui Ueyama return symVector[it->second]; 1021f3f774fSSam Clegg } 1031f3f774fSSam Clegg 104136d27abSRui Ueyama void SymbolTable::replace(StringRef name, Symbol* sym) { 105136d27abSRui Ueyama auto it = symMap.find(CachedHashStringRef(name)); 106136d27abSRui Ueyama symVector[it->second] = sym; 1076540e570SSam Clegg } 1086540e570SSam Clegg 109136d27abSRui Ueyama std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) { 110136d27abSRui Ueyama bool trace = false; 111136d27abSRui Ueyama auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 112136d27abSRui Ueyama int &symIndex = p.first->second; 113136d27abSRui Ueyama bool isNew = p.second; 114136d27abSRui Ueyama if (symIndex == -1) { 115136d27abSRui Ueyama symIndex = symVector.size(); 116136d27abSRui Ueyama trace = true; 117136d27abSRui Ueyama isNew = true; 1181f3f774fSSam Clegg } 1191f3f774fSSam Clegg 120136d27abSRui Ueyama if (!isNew) 121136d27abSRui Ueyama return {symVector[symIndex], false}; 1221f3f774fSSam Clegg 123136d27abSRui Ueyama Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 124136d27abSRui Ueyama sym->isUsedInRegularObj = false; 125136d27abSRui Ueyama sym->canInline = true; 126136d27abSRui Ueyama sym->traced = trace; 127064e9907SSam Clegg sym->forceExport = false; 1283792b362SFangrui Song sym->referenced = !ctx.arg.gcSections; 129136d27abSRui Ueyama symVector.emplace_back(sym); 130136d27abSRui Ueyama return {sym, true}; 131c94d393aSSam Clegg } 132c94d393aSSam Clegg 133136d27abSRui Ueyama std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, 134136d27abSRui Ueyama const InputFile *file) { 135136d27abSRui Ueyama Symbol *s; 136136d27abSRui Ueyama bool wasInserted; 137136d27abSRui Ueyama std::tie(s, wasInserted) = insertName(name); 1381f3f774fSSam Clegg 139136d27abSRui Ueyama if (!file || file->kind() == InputFile::ObjectKind) 140136d27abSRui Ueyama s->isUsedInRegularObj = true; 1411f3f774fSSam Clegg 142136d27abSRui Ueyama return {s, wasInserted}; 143c94d393aSSam Clegg } 144c94d393aSSam Clegg 145136d27abSRui Ueyama static void reportTypeError(const Symbol *existing, const InputFile *file, 146136d27abSRui Ueyama llvm::wasm::WasmSymbolType type) { 147136d27abSRui Ueyama error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " + 148136d27abSRui Ueyama toString(existing->getWasmType()) + " in " + 149136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined as " + toString(type) + 150136d27abSRui Ueyama " in " + toString(file)); 151e3498ec5SRui Ueyama } 152e3498ec5SRui Ueyama 1536f4286fbSHeejin Ahn // Check the type of new symbol matches that of the symbol is replacing. 1547c5fcb35SKazuaki Ishizaki // Returns true if the function types match, false is there is a signature 1556540e570SSam Clegg // mismatch. 156136d27abSRui Ueyama static bool signatureMatches(FunctionSymbol *existing, 157136d27abSRui Ueyama const WasmSignature *newSig) { 158136d27abSRui Ueyama const WasmSignature *oldSig = existing->signature; 159d506b0a4SSam Clegg 1609f903475SNico Weber // If either function is missing a signature (this happens for bitcode 161d506b0a4SSam Clegg // symbols) then assume they match. Any mismatch will be reported later 162d506b0a4SSam Clegg // when the LTO objects are added. 163136d27abSRui Ueyama if (!newSig || !oldSig) 1646540e570SSam Clegg return true; 165cefbf9acSSam Clegg 166136d27abSRui Ueyama return *newSig == *oldSig; 167e3498ec5SRui Ueyama } 168e3498ec5SRui Ueyama 169136d27abSRui Ueyama static void checkGlobalType(const Symbol *existing, const InputFile *file, 170136d27abSRui Ueyama const WasmGlobalType *newType) { 171136d27abSRui Ueyama if (!isa<GlobalSymbol>(existing)) { 172136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL); 173b8621596SSam Clegg return; 174b8621596SSam Clegg } 175b8621596SSam Clegg 176136d27abSRui Ueyama const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType(); 177136d27abSRui Ueyama if (*newType != *oldType) { 178136d27abSRui Ueyama error("Global type mismatch: " + existing->getName() + "\n>>> defined as " + 179136d27abSRui Ueyama toString(*oldType) + " in " + toString(existing->getFile()) + 180136d27abSRui Ueyama "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 181c94d393aSSam Clegg } 18224b3dcd4SSam Clegg } 18324b3dcd4SSam Clegg 1841d891d44SHeejin Ahn static void checkTagType(const Symbol *existing, const InputFile *file, 185136d27abSRui Ueyama const WasmSignature *newSig) { 1861d891d44SHeejin Ahn const auto *existingTag = dyn_cast<TagSymbol>(existing); 1871d891d44SHeejin Ahn if (!isa<TagSymbol>(existing)) { 1881d891d44SHeejin Ahn reportTypeError(existing, file, WASM_SYMBOL_TYPE_TAG); 189e915a71fSHeejin Ahn return; 190e915a71fSHeejin Ahn } 191e915a71fSHeejin Ahn 1921d891d44SHeejin Ahn const WasmSignature *oldSig = existingTag->signature; 193136d27abSRui Ueyama if (*newSig != *oldSig) 1941d891d44SHeejin Ahn warn("Tag signature mismatch: " + existing->getName() + 195136d27abSRui Ueyama "\n>>> defined as " + toString(*oldSig) + " in " + 196136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined as " + 197136d27abSRui Ueyama toString(*newSig) + " in " + toString(file)); 198e915a71fSHeejin Ahn } 199e915a71fSHeejin Ahn 20053e3b81fSAndy Wingo static void checkTableType(const Symbol *existing, const InputFile *file, 20153e3b81fSAndy Wingo const WasmTableType *newType) { 20253e3b81fSAndy Wingo if (!isa<TableSymbol>(existing)) { 20353e3b81fSAndy Wingo reportTypeError(existing, file, WASM_SYMBOL_TYPE_TABLE); 20453e3b81fSAndy Wingo return; 20553e3b81fSAndy Wingo } 20653e3b81fSAndy Wingo 20753e3b81fSAndy Wingo const WasmTableType *oldType = cast<TableSymbol>(existing)->getTableType(); 20853e3b81fSAndy Wingo if (newType->ElemType != oldType->ElemType) { 20953e3b81fSAndy Wingo error("Table type mismatch: " + existing->getName() + "\n>>> defined as " + 21053e3b81fSAndy Wingo toString(*oldType) + " in " + toString(existing->getFile()) + 21153e3b81fSAndy Wingo "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 21253e3b81fSAndy Wingo } 21353e3b81fSAndy Wingo // FIXME: No assertions currently on the limits. 21453e3b81fSAndy Wingo } 21553e3b81fSAndy Wingo 216136d27abSRui Ueyama static void checkDataType(const Symbol *existing, const InputFile *file) { 217136d27abSRui Ueyama if (!isa<DataSymbol>(existing)) 218136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA); 219e3498ec5SRui Ueyama } 220e3498ec5SRui Ueyama 221136d27abSRui Ueyama DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, 222136d27abSRui Ueyama uint32_t flags, 223136d27abSRui Ueyama InputFunction *function) { 224136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); 225136d27abSRui Ueyama assert(!find(name)); 2263c584570SSam Clegg ctx.syntheticFunctions.emplace_back(function); 227136d27abSRui Ueyama return replaceSymbol<DefinedFunction>(insertName(name).first, name, 228136d27abSRui Ueyama flags, nullptr, function); 22950686856SSam Clegg } 23050686856SSam Clegg 23129a3056bSSam Clegg // Adds an optional, linker generated, data symbol. The symbol will only be 2327ae3d335SKazuaki Ishizaki // added if there is an undefine reference to it, or if it is explicitly 2337ae3d335SKazuaki Ishizaki // exported via the --export flag. Otherwise we don't add the symbol and return 2347ae3d335SKazuaki Ishizaki // nullptr. 235caa0db13SSam Clegg DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, 236582fd474SWouter van Oortmerssen uint64_t value) { 237136d27abSRui Ueyama Symbol *s = find(name); 2383792b362SFangrui Song if (!s && (ctx.arg.exportAll || ctx.arg.exportedSymbols.count(name) != 0)) 239136d27abSRui Ueyama s = insertName(name).first; 240136d27abSRui Ueyama else if (!s || s->isDefined()) 2414bce63a0SSam Clegg return nullptr; 242136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n"); 243afe957eaSSam Clegg auto *rtn = replaceSymbol<DefinedData>( 244afe957eaSSam Clegg s, name, WASM_SYMBOL_VISIBILITY_HIDDEN | WASM_SYMBOL_ABSOLUTE); 24514ffbb84SSam Clegg rtn->setVA(value); 246136d27abSRui Ueyama rtn->referenced = true; 2474bce63a0SSam Clegg return rtn; 2484bce63a0SSam Clegg } 2494bce63a0SSam Clegg 250136d27abSRui Ueyama DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, 251136d27abSRui Ueyama uint32_t flags) { 252136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); 253136d27abSRui Ueyama assert(!find(name)); 254afe957eaSSam Clegg return replaceSymbol<DefinedData>(insertName(name).first, name, 255afe957eaSSam Clegg flags | WASM_SYMBOL_ABSOLUTE); 256c94d393aSSam Clegg } 257c94d393aSSam Clegg 258136d27abSRui Ueyama DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, 259136d27abSRui Ueyama InputGlobal *global) { 260136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global 261e7245b42SNicola Zaghen << "\n"); 262136d27abSRui Ueyama assert(!find(name)); 2633c584570SSam Clegg ctx.syntheticGlobals.emplace_back(global); 264136d27abSRui Ueyama return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags, 265136d27abSRui Ueyama nullptr, global); 26693102974SSam Clegg } 26793102974SSam Clegg 26888e4056bSSam Clegg DefinedGlobal *SymbolTable::addOptionalGlobalSymbol(StringRef name, 26929a3056bSSam Clegg InputGlobal *global) { 27029a3056bSSam Clegg Symbol *s = find(name); 27129a3056bSSam Clegg if (!s || s->isDefined()) 27229a3056bSSam Clegg return nullptr; 2738fe12847SSam Clegg LLVM_DEBUG(dbgs() << "addOptionalGlobalSymbol: " << name << " -> " << global 2748fe12847SSam Clegg << "\n"); 2753c584570SSam Clegg ctx.syntheticGlobals.emplace_back(global); 27688e4056bSSam Clegg return replaceSymbol<DefinedGlobal>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN, 27788e4056bSSam Clegg nullptr, global); 27829a3056bSSam Clegg } 27929a3056bSSam Clegg 28063393828SAndy Wingo DefinedTable *SymbolTable::addSyntheticTable(StringRef name, uint32_t flags, 28163393828SAndy Wingo InputTable *table) { 28263393828SAndy Wingo LLVM_DEBUG(dbgs() << "addSyntheticTable: " << name << " -> " << table 28363393828SAndy Wingo << "\n"); 28463393828SAndy Wingo Symbol *s = find(name); 28563393828SAndy Wingo assert(!s || s->isUndefined()); 28663393828SAndy Wingo if (!s) 28763393828SAndy Wingo s = insertName(name).first; 2883c584570SSam Clegg ctx.syntheticTables.emplace_back(table); 28963393828SAndy Wingo return replaceSymbol<DefinedTable>(s, name, flags, nullptr, table); 29063393828SAndy Wingo } 29163393828SAndy Wingo 292136d27abSRui Ueyama static bool shouldReplace(const Symbol *existing, InputFile *newFile, 293136d27abSRui Ueyama uint32_t newFlags) { 294c03c9040SRui Ueyama // If existing symbol is undefined, replace it. 295136d27abSRui Ueyama if (!existing->isDefined()) { 296e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 297136d27abSRui Ueyama << existing->getName() << "\n"); 298c03c9040SRui Ueyama return true; 299c03c9040SRui Ueyama } 300c03c9040SRui Ueyama 301c03c9040SRui Ueyama // Now we have two defined symbols. If the new one is weak, we can ignore it. 302136d27abSRui Ueyama if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 303e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 304c03c9040SRui Ueyama return false; 305c03c9040SRui Ueyama } 306c03c9040SRui Ueyama 307c03c9040SRui Ueyama // If the existing symbol is weak, we should replace it. 308136d27abSRui Ueyama if (existing->isWeak()) { 309e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 310c03c9040SRui Ueyama return true; 311c03c9040SRui Ueyama } 312c03c9040SRui Ueyama 31322b7b848SSam Clegg // Similarly with shared symbols 31422b7b848SSam Clegg if (existing->isShared()) { 31522b7b848SSam Clegg LLVM_DEBUG(dbgs() << "replacing existing shared symbol\n"); 31622b7b848SSam Clegg return true; 31722b7b848SSam Clegg } 31822b7b848SSam Clegg 319c03c9040SRui Ueyama // Neither symbol is week. They conflict. 3203792b362SFangrui Song if (ctx.arg.allowMultipleDefinition) 3210367305aSmzukovec return false; 3220367305aSmzukovec 3230367305aSmzukovec errorOrWarn("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + 324136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined in " + 325136d27abSRui Ueyama toString(newFile)); 326c03c9040SRui Ueyama return true; 327b8621596SSam Clegg } 32893e559b1SSam Clegg 32922b7b848SSam Clegg static void reportFunctionSignatureMismatch(StringRef symName, 33022b7b848SSam Clegg FunctionSymbol *sym, 33122b7b848SSam Clegg const WasmSignature *signature, 33222b7b848SSam Clegg InputFile *file, 33322b7b848SSam Clegg bool isError = true) { 33422b7b848SSam Clegg std::string msg = 33522b7b848SSam Clegg ("function signature mismatch: " + symName + "\n>>> defined as " + 33622b7b848SSam Clegg toString(*sym->signature) + " in " + toString(sym->getFile()) + 33722b7b848SSam Clegg "\n>>> defined as " + toString(*signature) + " in " + toString(file)) 33822b7b848SSam Clegg .str(); 33922b7b848SSam Clegg if (isError) 34022b7b848SSam Clegg error(msg); 34122b7b848SSam Clegg else 34222b7b848SSam Clegg warn(msg); 34322b7b848SSam Clegg } 34422b7b848SSam Clegg 34522b7b848SSam Clegg static void reportFunctionSignatureMismatch(StringRef symName, 34622b7b848SSam Clegg FunctionSymbol *a, 34722b7b848SSam Clegg FunctionSymbol *b, 34822b7b848SSam Clegg bool isError = true) { 34922b7b848SSam Clegg reportFunctionSignatureMismatch(symName, a, b->signature, b->getFile(), 35022b7b848SSam Clegg isError); 35122b7b848SSam Clegg } 35222b7b848SSam Clegg 35322b7b848SSam Clegg Symbol *SymbolTable::addSharedFunction(StringRef name, uint32_t flags, 35422b7b848SSam Clegg InputFile *file, 35522b7b848SSam Clegg const WasmSignature *sig) { 35622b7b848SSam Clegg LLVM_DEBUG(dbgs() << "addSharedFunction: " << name << " [" << toString(*sig) 35722b7b848SSam Clegg << "]\n"); 35822b7b848SSam Clegg Symbol *s; 35922b7b848SSam Clegg bool wasInserted; 36022b7b848SSam Clegg std::tie(s, wasInserted) = insert(name, file); 36122b7b848SSam Clegg 36222b7b848SSam Clegg auto replaceSym = [&](Symbol *sym) { 36322b7b848SSam Clegg replaceSymbol<SharedFunctionSymbol>(sym, name, flags, file, sig); 36422b7b848SSam Clegg }; 36522b7b848SSam Clegg 366*617278e7SSam Clegg if (wasInserted || s->isLazy()) { 36722b7b848SSam Clegg replaceSym(s); 36822b7b848SSam Clegg return s; 36922b7b848SSam Clegg } 37022b7b848SSam Clegg 37122b7b848SSam Clegg auto existingFunction = dyn_cast<FunctionSymbol>(s); 37222b7b848SSam Clegg if (!existingFunction) { 37322b7b848SSam Clegg reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 37422b7b848SSam Clegg return s; 37522b7b848SSam Clegg } 37622b7b848SSam Clegg 37722b7b848SSam Clegg // Shared symbols should never replace locally-defined ones 37822b7b848SSam Clegg if (s->isDefined()) { 37922b7b848SSam Clegg return s; 38022b7b848SSam Clegg } 38122b7b848SSam Clegg 38222b7b848SSam Clegg LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " << s->getName() 38322b7b848SSam Clegg << "\n"); 38422b7b848SSam Clegg 38522b7b848SSam Clegg bool checkSig = true; 38622b7b848SSam Clegg if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) 38722b7b848SSam Clegg checkSig = ud->isCalledDirectly; 38822b7b848SSam Clegg 38922b7b848SSam Clegg if (checkSig && !signatureMatches(existingFunction, sig)) { 3903792b362SFangrui Song if (ctx.arg.shlibSigCheck) { 39122b7b848SSam Clegg reportFunctionSignatureMismatch(name, existingFunction, sig, file); 39222b7b848SSam Clegg } else { 39322b7b848SSam Clegg // With --no-shlib-sigcheck we ignore the signature of the function as 39422b7b848SSam Clegg // defined by the shared library and instead use the signature as 39522b7b848SSam Clegg // expected by the program being linked. 39622b7b848SSam Clegg sig = existingFunction->signature; 39722b7b848SSam Clegg } 39822b7b848SSam Clegg } 39922b7b848SSam Clegg 40022b7b848SSam Clegg replaceSym(s); 40122b7b848SSam Clegg return s; 40222b7b848SSam Clegg } 40322b7b848SSam Clegg 40422b7b848SSam Clegg Symbol *SymbolTable::addSharedData(StringRef name, uint32_t flags, 40522b7b848SSam Clegg InputFile *file) { 40622b7b848SSam Clegg LLVM_DEBUG(dbgs() << "addSharedData: " << name << "\n"); 40722b7b848SSam Clegg Symbol *s; 40822b7b848SSam Clegg bool wasInserted; 40922b7b848SSam Clegg std::tie(s, wasInserted) = insert(name, file); 41022b7b848SSam Clegg 411*617278e7SSam Clegg if (wasInserted || s->isLazy()) { 41222b7b848SSam Clegg replaceSymbol<SharedData>(s, name, flags, file); 413*617278e7SSam Clegg return s; 41422b7b848SSam Clegg } 41522b7b848SSam Clegg 416*617278e7SSam Clegg // Shared symbols should never replace locally-defined ones 417*617278e7SSam Clegg if (s->isDefined()) { 418*617278e7SSam Clegg return s; 419*617278e7SSam Clegg } 420*617278e7SSam Clegg 421*617278e7SSam Clegg checkDataType(s, file); 422*617278e7SSam Clegg replaceSymbol<SharedData>(s, name, flags, file); 42322b7b848SSam Clegg return s; 42422b7b848SSam Clegg } 42522b7b848SSam Clegg 426136d27abSRui Ueyama Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags, 427136d27abSRui Ueyama InputFile *file, 428136d27abSRui Ueyama InputFunction *function) { 429136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " [" 430136d27abSRui Ueyama << (function ? toString(function->signature) : "none") 4318b0b48f3SSam Clegg << "]\n"); 432136d27abSRui Ueyama Symbol *s; 433136d27abSRui Ueyama bool wasInserted; 434136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 435c729c1b4SSam Clegg 436136d27abSRui Ueyama auto replaceSym = [&](Symbol *sym) { 4377c5fcb35SKazuaki Ishizaki // If the new defined function doesn't have signature (i.e. bitcode 4386540e570SSam Clegg // functions) but the old symbol does, then preserve the old signature 439136d27abSRui Ueyama const WasmSignature *oldSig = s->getSignature(); 440136d27abSRui Ueyama auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function); 441136d27abSRui Ueyama if (!newSym->signature) 442136d27abSRui Ueyama newSym->signature = oldSig; 4436540e570SSam Clegg }; 4446540e570SSam Clegg 445136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 446136d27abSRui Ueyama replaceSym(s); 447136d27abSRui Ueyama return s; 448e3498ec5SRui Ueyama } 449e3498ec5SRui Ueyama 450136d27abSRui Ueyama auto existingFunction = dyn_cast<FunctionSymbol>(s); 451136d27abSRui Ueyama if (!existingFunction) { 452136d27abSRui Ueyama reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 453136d27abSRui Ueyama return s; 4548b0b48f3SSam Clegg } 4556540e570SSam Clegg 456136d27abSRui Ueyama bool checkSig = true; 457136d27abSRui Ueyama if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) 458136d27abSRui Ueyama checkSig = ud->isCalledDirectly; 45959f959ffSSam Clegg 460136d27abSRui Ueyama if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) { 461136d27abSRui Ueyama Symbol* variant; 462136d27abSRui Ueyama if (getFunctionVariant(s, &function->signature, file, &variant)) 4636540e570SSam Clegg // New variant, always replace 464136d27abSRui Ueyama replaceSym(variant); 465136d27abSRui Ueyama else if (shouldReplace(s, file, flags)) 4666540e570SSam Clegg // Variant already exists, replace it after checking shouldReplace 467136d27abSRui Ueyama replaceSym(variant); 4686540e570SSam Clegg 4696540e570SSam Clegg // This variant we found take the place in the symbol table as the primary 4706540e570SSam Clegg // variant. 471136d27abSRui Ueyama replace(name, variant); 472136d27abSRui Ueyama return variant; 4736540e570SSam Clegg } 4746540e570SSam Clegg 4756540e570SSam Clegg // Existing function with matching signature. 476136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 477136d27abSRui Ueyama replaceSym(s); 4786540e570SSam Clegg 479136d27abSRui Ueyama return s; 48093e559b1SSam Clegg } 48193e559b1SSam Clegg 482136d27abSRui Ueyama Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, 4835a9b25e1SSam Clegg InputFile *file, InputChunk *segment, 4843b29376eSWouter van Oortmerssen uint64_t address, uint64_t size) { 485136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address 486e7245b42SNicola Zaghen << "\n"); 487136d27abSRui Ueyama Symbol *s; 488136d27abSRui Ueyama bool wasInserted; 489136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 490c729c1b4SSam Clegg 491136d27abSRui Ueyama auto replaceSym = [&]() { 492136d27abSRui Ueyama replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size); 4936540e570SSam Clegg }; 4946540e570SSam Clegg 495136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 496136d27abSRui Ueyama replaceSym(); 497136d27abSRui Ueyama return s; 498e3498ec5SRui Ueyama } 499e3498ec5SRui Ueyama 500136d27abSRui Ueyama checkDataType(s, file); 501e3498ec5SRui Ueyama 502136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 503136d27abSRui Ueyama replaceSym(); 504136d27abSRui Ueyama return s; 505c94d393aSSam Clegg } 506c94d393aSSam Clegg 507136d27abSRui Ueyama Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags, 508136d27abSRui Ueyama InputFile *file, InputGlobal *global) { 509136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n"); 5104c2cbfe6SSam Clegg 511136d27abSRui Ueyama Symbol *s; 512136d27abSRui Ueyama bool wasInserted; 513136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 514c729c1b4SSam Clegg 515136d27abSRui Ueyama auto replaceSym = [&]() { 516136d27abSRui Ueyama replaceSymbol<DefinedGlobal>(s, name, flags, file, global); 5176540e570SSam Clegg }; 5186540e570SSam Clegg 519136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 520136d27abSRui Ueyama replaceSym(); 521136d27abSRui Ueyama return s; 52293102974SSam Clegg } 52393102974SSam Clegg 524136d27abSRui Ueyama checkGlobalType(s, file, &global->getType()); 525e3498ec5SRui Ueyama 526136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 527136d27abSRui Ueyama replaceSym(); 528136d27abSRui Ueyama return s; 529e3498ec5SRui Ueyama } 530e3498ec5SRui Ueyama 5311d891d44SHeejin Ahn Symbol *SymbolTable::addDefinedTag(StringRef name, uint32_t flags, 5321d891d44SHeejin Ahn InputFile *file, InputTag *tag) { 5331d891d44SHeejin Ahn LLVM_DEBUG(dbgs() << "addDefinedTag:" << name << "\n"); 534e915a71fSHeejin Ahn 535136d27abSRui Ueyama Symbol *s; 536136d27abSRui Ueyama bool wasInserted; 537136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 538e915a71fSHeejin Ahn 539136d27abSRui Ueyama auto replaceSym = [&]() { 5401d891d44SHeejin Ahn replaceSymbol<DefinedTag>(s, name, flags, file, tag); 5416540e570SSam Clegg }; 5426540e570SSam Clegg 543136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 544136d27abSRui Ueyama replaceSym(); 545136d27abSRui Ueyama return s; 546e915a71fSHeejin Ahn } 547e915a71fSHeejin Ahn 5483ec1760dSHeejin Ahn checkTagType(s, file, &tag->signature); 549e915a71fSHeejin Ahn 550136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 551136d27abSRui Ueyama replaceSym(); 552136d27abSRui Ueyama return s; 553e915a71fSHeejin Ahn } 554e915a71fSHeejin Ahn 55553e3b81fSAndy Wingo Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags, 55653e3b81fSAndy Wingo InputFile *file, InputTable *table) { 55753e3b81fSAndy Wingo LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n"); 55853e3b81fSAndy Wingo 55953e3b81fSAndy Wingo Symbol *s; 56053e3b81fSAndy Wingo bool wasInserted; 56153e3b81fSAndy Wingo std::tie(s, wasInserted) = insert(name, file); 56253e3b81fSAndy Wingo 56353e3b81fSAndy Wingo auto replaceSym = [&]() { 56453e3b81fSAndy Wingo replaceSymbol<DefinedTable>(s, name, flags, file, table); 56553e3b81fSAndy Wingo }; 56653e3b81fSAndy Wingo 56753e3b81fSAndy Wingo if (wasInserted || s->isLazy()) { 56853e3b81fSAndy Wingo replaceSym(); 56953e3b81fSAndy Wingo return s; 57053e3b81fSAndy Wingo } 57153e3b81fSAndy Wingo 57253e3b81fSAndy Wingo checkTableType(s, file, &table->getType()); 57353e3b81fSAndy Wingo 57453e3b81fSAndy Wingo if (shouldReplace(s, file, flags)) 57553e3b81fSAndy Wingo replaceSym(); 57653e3b81fSAndy Wingo return s; 57753e3b81fSAndy Wingo } 57853e3b81fSAndy Wingo 57967b05584SSam Clegg // This function get called when an undefined symbol is added, and there is 58067b05584SSam Clegg // already an existing one in the symbols table. In this case we check that 58167b05584SSam Clegg // custom 'import-module' and 'import-field' symbol attributes agree. 5827ae3d335SKazuaki Ishizaki // With LTO these attributes are not available when the bitcode is read and only 58367b05584SSam Clegg // become available when the LTO object is read. In this case we silently 58467b05584SSam Clegg // replace the empty attributes with the valid ones. 58567b05584SSam Clegg template <typename T> 586b9ef5648SKazu Hirata static void setImportAttributes(T *existing, 587b9ef5648SKazu Hirata std::optional<StringRef> importName, 588b9ef5648SKazu Hirata std::optional<StringRef> importModule, 589a57f1a54SSam Clegg uint32_t flags, InputFile *file) { 590bd481277SSam Clegg if (importName) { 591bd481277SSam Clegg if (!existing->importName) 59267b05584SSam Clegg existing->importName = importName; 59367b05584SSam Clegg if (existing->importName != importName) 59467b05584SSam Clegg error("import name mismatch for symbol: " + toString(*existing) + 595bd481277SSam Clegg "\n>>> defined as " + *existing->importName + " in " + 596bd481277SSam Clegg toString(existing->getFile()) + "\n>>> defined as " + *importName + 59767b05584SSam Clegg " in " + toString(file)); 59867b05584SSam Clegg } 59967b05584SSam Clegg 600bd481277SSam Clegg if (importModule) { 601bd481277SSam Clegg if (!existing->importModule) 60267b05584SSam Clegg existing->importModule = importModule; 60367b05584SSam Clegg if (existing->importModule != importModule) 60467b05584SSam Clegg error("import module mismatch for symbol: " + toString(*existing) + 605bd481277SSam Clegg "\n>>> defined as " + *existing->importModule + " in " + 606bd481277SSam Clegg toString(existing->getFile()) + "\n>>> defined as " + 607bd481277SSam Clegg *importModule + " in " + toString(file)); 60867b05584SSam Clegg } 609a57f1a54SSam Clegg 610a57f1a54SSam Clegg // Update symbol binding, if the existing symbol is weak 611a57f1a54SSam Clegg uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK; 612a57f1a54SSam Clegg if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) { 613a57f1a54SSam Clegg existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding; 614a57f1a54SSam Clegg } 61567b05584SSam Clegg } 61667b05584SSam Clegg 617bd481277SSam Clegg Symbol *SymbolTable::addUndefinedFunction(StringRef name, 618b9ef5648SKazu Hirata std::optional<StringRef> importName, 619b9ef5648SKazu Hirata std::optional<StringRef> importModule, 620136d27abSRui Ueyama uint32_t flags, InputFile *file, 621136d27abSRui Ueyama const WasmSignature *sig, 622136d27abSRui Ueyama bool isCalledDirectly) { 623136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" 624136d27abSRui Ueyama << (sig ? toString(*sig) : "none") 625a57f1a54SSam Clegg << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x" 626a57f1a54SSam Clegg << utohexstr(flags) << "\n"); 627f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 628c03c9040SRui Ueyama 629136d27abSRui Ueyama Symbol *s; 630136d27abSRui Ueyama bool wasInserted; 631136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 632136d27abSRui Ueyama if (s->traced) 633136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 634c729c1b4SSam Clegg 635136d27abSRui Ueyama auto replaceSym = [&]() { 636136d27abSRui Ueyama replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags, 637136d27abSRui Ueyama file, sig, isCalledDirectly); 6386540e570SSam Clegg }; 6396540e570SSam Clegg 640b34ec596SSam Clegg if (wasInserted) { 641136d27abSRui Ueyama replaceSym(); 642b34ec596SSam Clegg } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 643b34ec596SSam Clegg if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 644b34ec596SSam Clegg lazy->setWeak(); 645b34ec596SSam Clegg lazy->signature = sig; 646b34ec596SSam Clegg } else { 647f2684959SSam Clegg lazy->extract(); 6483792b362SFangrui Song if (!ctx.arg.whyExtract.empty()) 649184c22ddSSam Clegg ctx.whyExtractRecords.emplace_back(toString(file), s->getFile(), *s); 650b34ec596SSam Clegg } 651b34ec596SSam Clegg } else { 652136d27abSRui Ueyama auto existingFunction = dyn_cast<FunctionSymbol>(s); 653136d27abSRui Ueyama if (!existingFunction) { 654136d27abSRui Ueyama reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 655136d27abSRui Ueyama return s; 6566540e570SSam Clegg } 657136d27abSRui Ueyama if (!existingFunction->signature && sig) 658136d27abSRui Ueyama existingFunction->signature = sig; 659a57f1a54SSam Clegg auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction); 660fecfc592SSam Clegg if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { 66122b7b848SSam Clegg if (existingFunction->isShared()) { 66222b7b848SSam Clegg // Special handling for when the existing function is a shared symbol 6633792b362SFangrui Song if (ctx.arg.shlibSigCheck) { 66422b7b848SSam Clegg reportFunctionSignatureMismatch(name, existingFunction, sig, file); 66522b7b848SSam Clegg } else { 66622b7b848SSam Clegg existingFunction->signature = sig; 66722b7b848SSam Clegg } 66822b7b848SSam Clegg } 669a57f1a54SSam Clegg // If the existing undefined functions is not called directly then let 670fecfc592SSam Clegg // this one take precedence. Otherwise the existing function is either 671a57f1a54SSam Clegg // directly called or defined, in which case we need a function variant. 67222b7b848SSam Clegg else if (existingUndefined && !existingUndefined->isCalledDirectly) 673136d27abSRui Ueyama replaceSym(); 674fecfc592SSam Clegg else if (getFunctionVariant(s, sig, file, &s)) 675fecfc592SSam Clegg replaceSym(); 676fecfc592SSam Clegg } 677e4888be7SSam Clegg if (existingUndefined) { 678a57f1a54SSam Clegg setImportAttributes(existingUndefined, importName, importModule, flags, 679a57f1a54SSam Clegg file); 680e4888be7SSam Clegg if (isCalledDirectly) 681e4888be7SSam Clegg existingUndefined->isCalledDirectly = true; 682d65ed8cdSSam Clegg if (s->isWeak()) 683d65ed8cdSSam Clegg s->flags = flags; 684e4888be7SSam Clegg } 6856540e570SSam Clegg } 686cefbf9acSSam Clegg 687136d27abSRui Ueyama return s; 688c03c9040SRui Ueyama } 689c03c9040SRui Ueyama 690136d27abSRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, 691136d27abSRui Ueyama InputFile *file) { 692136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); 693f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 69493102974SSam Clegg 695136d27abSRui Ueyama Symbol *s; 696136d27abSRui Ueyama bool wasInserted; 697136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 698136d27abSRui Ueyama if (s->traced) 699136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 700f989a92dSSam Clegg 701b34ec596SSam Clegg if (wasInserted) { 702136d27abSRui Ueyama replaceSymbol<UndefinedData>(s, name, flags, file); 703b34ec596SSam Clegg } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 704b34ec596SSam Clegg if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) 705b34ec596SSam Clegg lazy->setWeak(); 706b34ec596SSam Clegg else 707f2684959SSam Clegg lazy->extract(); 708b34ec596SSam Clegg } else if (s->isDefined()) { 709136d27abSRui Ueyama checkDataType(s, file); 710d65ed8cdSSam Clegg } else if (s->isWeak()) { 711d65ed8cdSSam Clegg s->flags = flags; 712b34ec596SSam Clegg } 713136d27abSRui Ueyama return s; 714c94d393aSSam Clegg } 715c94d393aSSam Clegg 716bd481277SSam Clegg Symbol *SymbolTable::addUndefinedGlobal(StringRef name, 717b9ef5648SKazu Hirata std::optional<StringRef> importName, 718b9ef5648SKazu Hirata std::optional<StringRef> importModule, 719bd481277SSam Clegg uint32_t flags, InputFile *file, 720136d27abSRui Ueyama const WasmGlobalType *type) { 721136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); 722f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 723e3498ec5SRui Ueyama 724136d27abSRui Ueyama Symbol *s; 725136d27abSRui Ueyama bool wasInserted; 726136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 727136d27abSRui Ueyama if (s->traced) 728136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 729c729c1b4SSam Clegg 730136d27abSRui Ueyama if (wasInserted) 731136d27abSRui Ueyama replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, 732136d27abSRui Ueyama file, type); 733136d27abSRui Ueyama else if (auto *lazy = dyn_cast<LazySymbol>(s)) 734f2684959SSam Clegg lazy->extract(); 735136d27abSRui Ueyama else if (s->isDefined()) 736136d27abSRui Ueyama checkGlobalType(s, file, type); 737d65ed8cdSSam Clegg else if (s->isWeak()) 738d65ed8cdSSam Clegg s->flags = flags; 739136d27abSRui Ueyama return s; 740e3498ec5SRui Ueyama } 741e3498ec5SRui Ueyama 74253e3b81fSAndy Wingo Symbol *SymbolTable::addUndefinedTable(StringRef name, 743b9ef5648SKazu Hirata std::optional<StringRef> importName, 744b9ef5648SKazu Hirata std::optional<StringRef> importModule, 74553e3b81fSAndy Wingo uint32_t flags, InputFile *file, 74653e3b81fSAndy Wingo const WasmTableType *type) { 74753e3b81fSAndy Wingo LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n"); 74853e3b81fSAndy Wingo assert(flags & WASM_SYMBOL_UNDEFINED); 74953e3b81fSAndy Wingo 75053e3b81fSAndy Wingo Symbol *s; 75153e3b81fSAndy Wingo bool wasInserted; 75253e3b81fSAndy Wingo std::tie(s, wasInserted) = insert(name, file); 75353e3b81fSAndy Wingo if (s->traced) 75453e3b81fSAndy Wingo printTraceSymbolUndefined(name, file); 75553e3b81fSAndy Wingo 75653e3b81fSAndy Wingo if (wasInserted) 75753e3b81fSAndy Wingo replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags, 75853e3b81fSAndy Wingo file, type); 75953e3b81fSAndy Wingo else if (auto *lazy = dyn_cast<LazySymbol>(s)) 760f2684959SSam Clegg lazy->extract(); 76153e3b81fSAndy Wingo else if (s->isDefined()) 76253e3b81fSAndy Wingo checkTableType(s, file, type); 763d65ed8cdSSam Clegg else if (s->isWeak()) 764d65ed8cdSSam Clegg s->flags = flags; 76553e3b81fSAndy Wingo return s; 76653e3b81fSAndy Wingo } 76753e3b81fSAndy Wingo 7689261ee32SHeejin Ahn Symbol *SymbolTable::addUndefinedTag(StringRef name, 769b9ef5648SKazu Hirata std::optional<StringRef> importName, 770b9ef5648SKazu Hirata std::optional<StringRef> importModule, 7719261ee32SHeejin Ahn uint32_t flags, InputFile *file, 7729261ee32SHeejin Ahn const WasmSignature *sig) { 7739261ee32SHeejin Ahn LLVM_DEBUG(dbgs() << "addUndefinedTag: " << name << "\n"); 7749261ee32SHeejin Ahn assert(flags & WASM_SYMBOL_UNDEFINED); 7759261ee32SHeejin Ahn 7769261ee32SHeejin Ahn Symbol *s; 7779261ee32SHeejin Ahn bool wasInserted; 7789261ee32SHeejin Ahn std::tie(s, wasInserted) = insert(name, file); 7799261ee32SHeejin Ahn if (s->traced) 7809261ee32SHeejin Ahn printTraceSymbolUndefined(name, file); 7819261ee32SHeejin Ahn 7829261ee32SHeejin Ahn if (wasInserted) 7839261ee32SHeejin Ahn replaceSymbol<UndefinedTag>(s, name, importName, importModule, flags, file, 7849261ee32SHeejin Ahn sig); 7859261ee32SHeejin Ahn else if (auto *lazy = dyn_cast<LazySymbol>(s)) 786f2684959SSam Clegg lazy->extract(); 7879261ee32SHeejin Ahn else if (s->isDefined()) 7889261ee32SHeejin Ahn checkTagType(s, file, sig); 789d65ed8cdSSam Clegg else if (s->isWeak()) 790d65ed8cdSSam Clegg s->flags = flags; 7919261ee32SHeejin Ahn return s; 7929261ee32SHeejin Ahn } 7939261ee32SHeejin Ahn 794e638d8b2SAndy Wingo TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) { 795e638d8b2SAndy Wingo WasmLimits limits{0, 0, 0}; // Set by the writer. 796e638d8b2SAndy Wingo WasmTableType *type = make<WasmTableType>(); 797103fa325SDerek Schuff type->ElemType = ValType::FUNCREF; 798e638d8b2SAndy Wingo type->Limits = limits; 7993792b362SFangrui Song uint32_t flags = ctx.arg.exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; 800e638d8b2SAndy Wingo flags |= WASM_SYMBOL_UNDEFINED; 8010fb33515SSam Clegg Symbol *sym = 8020fb33515SSam Clegg addUndefinedTable(name, name, defaultModule, flags, nullptr, type); 803e638d8b2SAndy Wingo sym->markLive(); 8043792b362SFangrui Song sym->forceExport = ctx.arg.exportTable; 805e638d8b2SAndy Wingo return cast<TableSymbol>(sym); 806e638d8b2SAndy Wingo } 807e638d8b2SAndy Wingo 808e638d8b2SAndy Wingo TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) { 809e638d8b2SAndy Wingo const uint32_t invalidIndex = -1; 810e638d8b2SAndy Wingo WasmLimits limits{0, 0, 0}; // Set by the writer. 811103fa325SDerek Schuff WasmTableType type{ValType::FUNCREF, limits}; 812e638d8b2SAndy Wingo WasmTable desc{invalidIndex, type, name}; 813e638d8b2SAndy Wingo InputTable *table = make<InputTable>(desc, nullptr); 8143792b362SFangrui Song uint32_t flags = ctx.arg.exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; 815e638d8b2SAndy Wingo TableSymbol *sym = addSyntheticTable(name, flags, table); 816e638d8b2SAndy Wingo sym->markLive(); 8173792b362SFangrui Song sym->forceExport = ctx.arg.exportTable; 818e638d8b2SAndy Wingo return sym; 819e638d8b2SAndy Wingo } 820e638d8b2SAndy Wingo 821e638d8b2SAndy Wingo // Whether or not we need an indirect function table is usually a function of 822e638d8b2SAndy Wingo // whether an input declares a need for it. However sometimes it's possible for 823e638d8b2SAndy Wingo // no input to need the indirect function table, but then a late 824e638d8b2SAndy Wingo // addInternalGOTEntry causes a function to be allocated an address. In that 825e638d8b2SAndy Wingo // case address we synthesize a definition at the last minute. 826e638d8b2SAndy Wingo TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) { 827e638d8b2SAndy Wingo Symbol *existing = find(functionTableName); 828e638d8b2SAndy Wingo if (existing) { 829e638d8b2SAndy Wingo if (!isa<TableSymbol>(existing)) { 830e638d8b2SAndy Wingo error(Twine("reserved symbol must be of type table: `") + 831e638d8b2SAndy Wingo functionTableName + "`"); 832e638d8b2SAndy Wingo return nullptr; 833e638d8b2SAndy Wingo } 834e638d8b2SAndy Wingo if (existing->isDefined()) { 835e638d8b2SAndy Wingo error(Twine("reserved symbol must not be defined in input files: `") + 836e638d8b2SAndy Wingo functionTableName + "`"); 837e638d8b2SAndy Wingo return nullptr; 838e638d8b2SAndy Wingo } 839e638d8b2SAndy Wingo } 840e638d8b2SAndy Wingo 8413792b362SFangrui Song if (ctx.arg.importTable) { 8420fb33515SSam Clegg if (existing) { 8430fb33515SSam Clegg existing->importModule = defaultModule; 8440fb33515SSam Clegg existing->importName = functionTableName; 845e638d8b2SAndy Wingo return cast<TableSymbol>(existing); 8460fb33515SSam Clegg } 847e638d8b2SAndy Wingo if (required) 848e638d8b2SAndy Wingo return createUndefinedIndirectFunctionTable(functionTableName); 8493792b362SFangrui Song } else if ((existing && existing->isLive()) || ctx.arg.exportTable || 850e638d8b2SAndy Wingo required) { 851e638d8b2SAndy Wingo // A defined table is required. Either because the user request an exported 852e638d8b2SAndy Wingo // table or because the table symbol is already live. The existing table is 853e638d8b2SAndy Wingo // guaranteed to be undefined due to the check above. 854e638d8b2SAndy Wingo return createDefinedIndirectFunctionTable(functionTableName); 855e638d8b2SAndy Wingo } 856e638d8b2SAndy Wingo 857e638d8b2SAndy Wingo // An indirect function table will only be present in the symbol table if 858e638d8b2SAndy Wingo // needed by a reloc; if we get here, we don't need one. 859e638d8b2SAndy Wingo return nullptr; 860e638d8b2SAndy Wingo } 861e638d8b2SAndy Wingo 862bcc9b9d8SSam Clegg void SymbolTable::addLazy(StringRef name, InputFile *file) { 863bcc9b9d8SSam Clegg LLVM_DEBUG(dbgs() << "addLazy: " << name << "\n"); 864c03c9040SRui Ueyama 865136d27abSRui Ueyama Symbol *s; 866136d27abSRui Ueyama bool wasInserted; 867136d27abSRui Ueyama std::tie(s, wasInserted) = insertName(name); 868c03c9040SRui Ueyama 869136d27abSRui Ueyama if (wasInserted) { 870bcc9b9d8SSam Clegg replaceSymbol<LazySymbol>(s, name, 0, file); 871c03c9040SRui Ueyama return; 872c03c9040SRui Ueyama } 873c03c9040SRui Ueyama 874136d27abSRui Ueyama if (!s->isUndefined()) 87537b4ee52SSam Clegg return; 87637b4ee52SSam Clegg 87737b4ee52SSam Clegg // The existing symbol is undefined, load a new one from the archive, 8787ae3d335SKazuaki Ishizaki // unless the existing symbol is weak in which case replace the undefined 87937b4ee52SSam Clegg // symbols with a LazySymbol. 880136d27abSRui Ueyama if (s->isWeak()) { 881136d27abSRui Ueyama const WasmSignature *oldSig = nullptr; 88237b4ee52SSam Clegg // In the case of an UndefinedFunction we need to preserve the expected 88337b4ee52SSam Clegg // signature. 884136d27abSRui Ueyama if (auto *f = dyn_cast<UndefinedFunction>(s)) 885136d27abSRui Ueyama oldSig = f->signature; 88637b4ee52SSam Clegg LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 887bcc9b9d8SSam Clegg auto newSym = 888bcc9b9d8SSam Clegg replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, file); 889136d27abSRui Ueyama newSym->signature = oldSig; 89037b4ee52SSam Clegg return; 89137b4ee52SSam Clegg } 89237b4ee52SSam Clegg 893e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 8948aef04faSSam Clegg const InputFile *oldFile = s->getFile(); 89558d5a486SSam Clegg LazySymbol(name, 0, file).extract(); 8963792b362SFangrui Song if (!ctx.arg.whyExtract.empty()) 897184c22ddSSam Clegg ctx.whyExtractRecords.emplace_back(toString(oldFile), s->getFile(), *s); 898c94d393aSSam Clegg } 899e0f6fcd0SSam Clegg 900136d27abSRui Ueyama bool SymbolTable::addComdat(StringRef name) { 901136d27abSRui Ueyama return comdatGroups.insert(CachedHashStringRef(name)).second; 902e0f6fcd0SSam Clegg } 9031f3f774fSSam Clegg 9046540e570SSam Clegg // The new signature doesn't match. Create a variant to the symbol with the 9056540e570SSam Clegg // signature encoded in the name and return that instead. These symbols are 9066540e570SSam Clegg // then unified later in handleSymbolVariants. 907136d27abSRui Ueyama bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, 908136d27abSRui Ueyama const InputFile *file, Symbol **out) { 909136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " 910136d27abSRui Ueyama << " " << toString(*sig) << "\n"); 911136d27abSRui Ueyama Symbol *variant = nullptr; 9126540e570SSam Clegg 9136540e570SSam Clegg // Linear search through symbol variants. Should never be more than two 9146540e570SSam Clegg // or three entries here. 915136d27abSRui Ueyama auto &variants = symVariants[CachedHashStringRef(sym->getName())]; 916136d27abSRui Ueyama if (variants.empty()) 917136d27abSRui Ueyama variants.push_back(sym); 9186540e570SSam Clegg 919136d27abSRui Ueyama for (Symbol* v : variants) { 920136d27abSRui Ueyama if (*v->getSignature() == *sig) { 921136d27abSRui Ueyama variant = v; 9226540e570SSam Clegg break; 9236540e570SSam Clegg } 9246540e570SSam Clegg } 9256540e570SSam Clegg 926136d27abSRui Ueyama bool wasAdded = !variant; 927136d27abSRui Ueyama if (wasAdded) { 9286540e570SSam Clegg // Create a new variant; 9296540e570SSam Clegg LLVM_DEBUG(dbgs() << "added new variant\n"); 930136d27abSRui Ueyama variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 931064e9907SSam Clegg variant->isUsedInRegularObj = 932064e9907SSam Clegg !file || file->kind() == InputFile::ObjectKind; 933064e9907SSam Clegg variant->canInline = true; 934064e9907SSam Clegg variant->traced = false; 935064e9907SSam Clegg variant->forceExport = false; 936136d27abSRui Ueyama variants.push_back(variant); 9376540e570SSam Clegg } else { 938136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); 939136d27abSRui Ueyama assert(*variant->getSignature() == *sig); 9406540e570SSam Clegg } 9416540e570SSam Clegg 942136d27abSRui Ueyama *out = variant; 943136d27abSRui Ueyama return wasAdded; 9446540e570SSam Clegg } 9456540e570SSam Clegg 9461f3f774fSSam Clegg // Set a flag for --trace-symbol so that we can print out a log message 9471f3f774fSSam Clegg // if a new symbol with the same name is inserted into the symbol table. 948136d27abSRui Ueyama void SymbolTable::trace(StringRef name) { 949136d27abSRui Ueyama symMap.insert({CachedHashStringRef(name), -1}); 9501f3f774fSSam Clegg } 951230dc11dSSam Clegg 952136d27abSRui Ueyama void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { 953a5ca34e6SSam Clegg // Swap symbols as instructed by -wrap. 954136d27abSRui Ueyama int &origIdx = symMap[CachedHashStringRef(sym->getName())]; 955136d27abSRui Ueyama int &realIdx= symMap[CachedHashStringRef(real->getName())]; 956136d27abSRui Ueyama int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; 957136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); 958a5ca34e6SSam Clegg 959a5ca34e6SSam Clegg // Anyone looking up __real symbols should get the original 960136d27abSRui Ueyama realIdx = origIdx; 961a5ca34e6SSam Clegg // Anyone looking up the original should get the __wrap symbol 962136d27abSRui Ueyama origIdx = wrapIdx; 963a5ca34e6SSam Clegg } 964a5ca34e6SSam Clegg 965136d27abSRui Ueyama static const uint8_t unreachableFn[] = { 966230dc11dSSam Clegg 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 967230dc11dSSam Clegg 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 968230dc11dSSam Clegg }; 969230dc11dSSam Clegg 970230dc11dSSam Clegg // Replace the given symbol body with an unreachable function. 971230dc11dSSam Clegg // This is used by handleWeakUndefines in order to generate a callable 9726540e570SSam Clegg // equivalent of an undefined function and also handleSymbolVariants for 9736540e570SSam Clegg // undefined functions that don't match the signature of the definition. 974136d27abSRui Ueyama InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, 975136d27abSRui Ueyama const WasmSignature &sig, 976136d27abSRui Ueyama StringRef debugName) { 977136d27abSRui Ueyama auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); 978136d27abSRui Ueyama func->setBody(unreachableFn); 9793c584570SSam Clegg ctx.syntheticFunctions.emplace_back(func); 9804b8e2d8eSSam Clegg // Mark new symbols as local. For relocatable output we don't want them 9814b8e2d8eSSam Clegg // to be exported outside the object file. 9824b8e2d8eSSam Clegg replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL, 9834b8e2d8eSSam Clegg nullptr, func); 98448ddf5e1SSam Clegg // Ensure the stub function doesn't get a table entry. Its address 98548ddf5e1SSam Clegg // should always compare equal to the null pointer. 98648ddf5e1SSam Clegg sym->isStub = true; 987136d27abSRui Ueyama return func; 988230dc11dSSam Clegg } 989230dc11dSSam Clegg 990206884bfSSam Clegg void SymbolTable::replaceWithUndefined(Symbol *sym) { 991206884bfSSam Clegg // Add a synthetic dummy for weak undefined functions. These dummies will 992206884bfSSam Clegg // be GC'd if not used as the target of any "call" instructions. 99383d59e05SAlexandre Ganea StringRef debugName = saver().save("undefined_weak:" + toString(*sym)); 994206884bfSSam Clegg replaceWithUnreachable(sym, *sym->getSignature(), debugName); 995206884bfSSam Clegg // Hide our dummy to prevent export. 996206884bfSSam Clegg sym->setHidden(true); 997206884bfSSam Clegg } 998206884bfSSam Clegg 999230dc11dSSam Clegg // For weak undefined functions, there may be "call" instructions that reference 1000230dc11dSSam Clegg // the symbol. In this case, we need to synthesise a dummy/stub function that 1001230dc11dSSam Clegg // will abort at runtime, so that relocations can still provided an operand to 1002230dc11dSSam Clegg // the call instruction that passes Wasm validation. 1003230dc11dSSam Clegg void SymbolTable::handleWeakUndefines() { 1004113b5688SSam Clegg for (Symbol *sym : symbols()) { 10050e8f4ce3SSam Clegg if (sym->isUndefWeak() && sym->isUsedInRegularObj) { 1006206884bfSSam Clegg if (sym->getSignature()) { 1007206884bfSSam Clegg replaceWithUndefined(sym); 1008206884bfSSam Clegg } else { 1009206884bfSSam Clegg // It is possible for undefined functions not to have a signature (eg. 1010206884bfSSam Clegg // if added via "--undefined"), but weak undefined ones do have a 1011206884bfSSam Clegg // signature. Lazy symbols may not be functions and therefore Sig can 1012206884bfSSam Clegg // still be null in some circumstance. 1013136d27abSRui Ueyama assert(!isa<FunctionSymbol>(sym)); 1014206884bfSSam Clegg } 1015206884bfSSam Clegg } 1016206884bfSSam Clegg } 10176540e570SSam Clegg } 1018230dc11dSSam Clegg 1019206884bfSSam Clegg DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) { 1020fd87188cSKazu Hirata if (auto it = stubFunctions.find(sig); it != stubFunctions.end()) 1021fd87188cSKazu Hirata return it->second; 1022206884bfSSam Clegg LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n"); 1023206884bfSSam Clegg auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>()); 1024206884bfSSam Clegg sym->isUsedInRegularObj = true; 1025206884bfSSam Clegg sym->canInline = true; 1026206884bfSSam Clegg sym->traced = false; 1027206884bfSSam Clegg sym->forceExport = false; 1028206884bfSSam Clegg sym->signature = &sig; 1029206884bfSSam Clegg replaceSymbol<DefinedFunction>( 1030206884bfSSam Clegg sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr); 1031206884bfSSam Clegg replaceWithUnreachable(sym, sig, "undefined_stub"); 1032206884bfSSam Clegg stubFunctions[sig] = sym; 1033206884bfSSam Clegg return sym; 1034230dc11dSSam Clegg } 10356540e570SSam Clegg 10366540e570SSam Clegg // Remove any variant symbols that were created due to function signature 10376540e570SSam Clegg // mismatches. 10386540e570SSam Clegg void SymbolTable::handleSymbolVariants() { 1039136d27abSRui Ueyama for (auto pair : symVariants) { 10406540e570SSam Clegg // Push the initial symbol onto the list of variants. 1041136d27abSRui Ueyama StringRef symName = pair.first.val(); 1042136d27abSRui Ueyama std::vector<Symbol *> &variants = pair.second; 10436540e570SSam Clegg 10446540e570SSam Clegg #ifndef NDEBUG 1045136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() 1046136d27abSRui Ueyama << ") variants: " << symName << "\n"); 1047136d27abSRui Ueyama for (auto *s: variants) { 1048136d27abSRui Ueyama auto *f = cast<FunctionSymbol>(s); 1049136d27abSRui Ueyama LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " 1050136d27abSRui Ueyama << toString(*f->signature) << "\n"); 10516540e570SSam Clegg } 10526540e570SSam Clegg #endif 10536540e570SSam Clegg 10546540e570SSam Clegg // Find the one definition. 1055136d27abSRui Ueyama DefinedFunction *defined = nullptr; 1056136d27abSRui Ueyama for (auto *symbol : variants) { 1057136d27abSRui Ueyama if (auto f = dyn_cast<DefinedFunction>(symbol)) { 1058136d27abSRui Ueyama defined = f; 10596540e570SSam Clegg break; 10606540e570SSam Clegg } 10616540e570SSam Clegg } 10626540e570SSam Clegg 10636540e570SSam Clegg // If there are no definitions, and the undefined symbols disagree on 10646540e570SSam Clegg // the signature, there is not we can do since we don't know which one 10656540e570SSam Clegg // to use as the signature on the import. 1066136d27abSRui Ueyama if (!defined) { 1067136d27abSRui Ueyama reportFunctionSignatureMismatch(symName, 1068136d27abSRui Ueyama cast<FunctionSymbol>(variants[0]), 106922b7b848SSam Clegg cast<FunctionSymbol>(variants[1])); 10706540e570SSam Clegg return; 10716540e570SSam Clegg } 10726540e570SSam Clegg 1073136d27abSRui Ueyama for (auto *symbol : variants) { 1074136d27abSRui Ueyama if (symbol != defined) { 1075136d27abSRui Ueyama auto *f = cast<FunctionSymbol>(symbol); 1076136d27abSRui Ueyama reportFunctionSignatureMismatch(symName, f, defined, false); 107783d59e05SAlexandre Ganea StringRef debugName = 107883d59e05SAlexandre Ganea saver().save("signature_mismatch:" + toString(*f)); 1079136d27abSRui Ueyama replaceWithUnreachable(f, *f->signature, debugName); 10806540e570SSam Clegg } 10816540e570SSam Clegg } 10826540e570SSam Clegg } 10836540e570SSam Clegg } 108433c59abfSFangrui Song 1085d32f71a9SSam Clegg } // namespace wasm::lld 1086