1c94d393aSSam Clegg //===- SymbolTable.cpp ----------------------------------------------------===// 2c94d393aSSam Clegg // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c94d393aSSam Clegg // 7c94d393aSSam Clegg //===----------------------------------------------------------------------===// 8c94d393aSSam Clegg 9c94d393aSSam Clegg #include "SymbolTable.h" 10c94d393aSSam Clegg #include "Config.h" 115fa274beSSam Clegg #include "InputChunks.h" 12e915a71fSHeejin Ahn #include "InputEvent.h" 1393102974SSam Clegg #include "InputGlobal.h" 1453e3b81fSAndy Wingo #include "InputTable.h" 15b8621596SSam Clegg #include "WriterUtils.h" 16c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h" 172017d52bSRui Ueyama #include "lld/Common/Memory.h" 187d67dd11SRui Ueyama #include "llvm/ADT/SetVector.h" 19c94d393aSSam Clegg 20c94d393aSSam Clegg #define DEBUG_TYPE "lld" 21c94d393aSSam Clegg 22c94d393aSSam Clegg using namespace llvm; 2320db381bSSam Clegg using namespace llvm::wasm; 2445218f4aSSam Clegg using namespace llvm::object; 25c94d393aSSam Clegg 2633c59abfSFangrui Song namespace lld { 2733c59abfSFangrui Song namespace wasm { 2833c59abfSFangrui Song SymbolTable *symtab; 29c94d393aSSam Clegg 30136d27abSRui Ueyama void SymbolTable::addFile(InputFile *file) { 31136d27abSRui Ueyama log("Processing: " + toString(file)); 32a282a61bSSam Clegg 33a282a61bSSam Clegg // .a file 34136d27abSRui Ueyama if (auto *f = dyn_cast<ArchiveFile>(file)) { 35136d27abSRui Ueyama f->parse(); 36a282a61bSSam Clegg return; 37a282a61bSSam Clegg } 38a282a61bSSam Clegg 39a282a61bSSam Clegg // .so file 40136d27abSRui Ueyama if (auto *f = dyn_cast<SharedFile>(file)) { 41136d27abSRui Ueyama sharedFiles.push_back(f); 42a282a61bSSam Clegg return; 43a282a61bSSam Clegg } 44a282a61bSSam Clegg 45136d27abSRui Ueyama if (config->trace) 46136d27abSRui Ueyama message(toString(file)); 47c94d393aSSam Clegg 48c729c1b4SSam Clegg // LLVM bitcode file 49136d27abSRui Ueyama if (auto *f = dyn_cast<BitcodeFile>(file)) { 50136d27abSRui Ueyama f->parse(); 51136d27abSRui Ueyama bitcodeFiles.push_back(f); 52a282a61bSSam Clegg return; 53a282a61bSSam Clegg } 54a282a61bSSam Clegg 55a282a61bSSam Clegg // Regular object file 56136d27abSRui Ueyama auto *f = cast<ObjFile>(file); 57136d27abSRui Ueyama f->parse(false); 58136d27abSRui Ueyama objectFiles.push_back(f); 59c94d393aSSam Clegg } 60c94d393aSSam Clegg 61c729c1b4SSam Clegg // This function is where all the optimizations of link-time 62c729c1b4SSam Clegg // optimization happens. When LTO is in use, some input files are 63c729c1b4SSam Clegg // not in native object file format but in the LLVM bitcode format. 64c729c1b4SSam Clegg // This function compiles bitcode files into a few big native files 65c729c1b4SSam Clegg // using LLVM functions and replaces bitcode symbols with the results. 66c729c1b4SSam Clegg // Because all bitcode files that the program consists of are passed 67c729c1b4SSam Clegg // to the compiler at once, it can do whole-program optimization. 68c729c1b4SSam Clegg void SymbolTable::addCombinedLTOObject() { 69b062fe18SSam Clegg // Prevent further LTO objects being included 70b062fe18SSam Clegg BitcodeFile::doneLTO = true; 71b062fe18SSam Clegg 72136d27abSRui Ueyama if (bitcodeFiles.empty()) 73c729c1b4SSam Clegg return; 74c729c1b4SSam Clegg 75c729c1b4SSam Clegg // Compile bitcode files and replace bitcode symbols. 76136d27abSRui Ueyama lto.reset(new BitcodeCompiler); 77136d27abSRui Ueyama for (BitcodeFile *f : bitcodeFiles) 78136d27abSRui Ueyama lto->add(*f); 79c729c1b4SSam Clegg 80136d27abSRui Ueyama for (StringRef filename : lto->compile()) { 81136d27abSRui Ueyama auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), ""); 82136d27abSRui Ueyama obj->parse(true); 83136d27abSRui Ueyama objectFiles.push_back(obj); 84c729c1b4SSam Clegg } 85c729c1b4SSam Clegg } 86c729c1b4SSam Clegg 87136d27abSRui Ueyama Symbol *SymbolTable::find(StringRef name) { 88136d27abSRui Ueyama auto it = symMap.find(CachedHashStringRef(name)); 89136d27abSRui Ueyama if (it == symMap.end() || it->second == -1) 901f3f774fSSam Clegg return nullptr; 91136d27abSRui Ueyama return symVector[it->second]; 921f3f774fSSam Clegg } 931f3f774fSSam Clegg 94136d27abSRui Ueyama void SymbolTable::replace(StringRef name, Symbol* sym) { 95136d27abSRui Ueyama auto it = symMap.find(CachedHashStringRef(name)); 96136d27abSRui Ueyama symVector[it->second] = sym; 976540e570SSam Clegg } 986540e570SSam Clegg 99136d27abSRui Ueyama std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) { 100136d27abSRui Ueyama bool trace = false; 101136d27abSRui Ueyama auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 102136d27abSRui Ueyama int &symIndex = p.first->second; 103136d27abSRui Ueyama bool isNew = p.second; 104136d27abSRui Ueyama if (symIndex == -1) { 105136d27abSRui Ueyama symIndex = symVector.size(); 106136d27abSRui Ueyama trace = true; 107136d27abSRui Ueyama isNew = true; 1081f3f774fSSam Clegg } 1091f3f774fSSam Clegg 110136d27abSRui Ueyama if (!isNew) 111136d27abSRui Ueyama return {symVector[symIndex], false}; 1121f3f774fSSam Clegg 113136d27abSRui Ueyama Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 114136d27abSRui Ueyama sym->isUsedInRegularObj = false; 115136d27abSRui Ueyama sym->canInline = true; 116136d27abSRui Ueyama sym->traced = trace; 117064e9907SSam Clegg sym->forceExport = false; 118136d27abSRui Ueyama symVector.emplace_back(sym); 119136d27abSRui Ueyama return {sym, true}; 120c94d393aSSam Clegg } 121c94d393aSSam Clegg 122136d27abSRui Ueyama std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, 123136d27abSRui Ueyama const InputFile *file) { 124136d27abSRui Ueyama Symbol *s; 125136d27abSRui Ueyama bool wasInserted; 126136d27abSRui Ueyama std::tie(s, wasInserted) = insertName(name); 1271f3f774fSSam Clegg 128136d27abSRui Ueyama if (!file || file->kind() == InputFile::ObjectKind) 129136d27abSRui Ueyama s->isUsedInRegularObj = true; 1301f3f774fSSam Clegg 131136d27abSRui Ueyama return {s, wasInserted}; 132c94d393aSSam Clegg } 133c94d393aSSam Clegg 134136d27abSRui Ueyama static void reportTypeError(const Symbol *existing, const InputFile *file, 135136d27abSRui Ueyama llvm::wasm::WasmSymbolType type) { 136136d27abSRui Ueyama error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " + 137136d27abSRui Ueyama toString(existing->getWasmType()) + " in " + 138136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined as " + toString(type) + 139136d27abSRui Ueyama " in " + toString(file)); 140e3498ec5SRui Ueyama } 141e3498ec5SRui Ueyama 1426f4286fbSHeejin Ahn // Check the type of new symbol matches that of the symbol is replacing. 1437c5fcb35SKazuaki Ishizaki // Returns true if the function types match, false is there is a signature 1446540e570SSam Clegg // mismatch. 145136d27abSRui Ueyama static bool signatureMatches(FunctionSymbol *existing, 146136d27abSRui Ueyama const WasmSignature *newSig) { 147136d27abSRui Ueyama const WasmSignature *oldSig = existing->signature; 148d506b0a4SSam Clegg 149d506b0a4SSam Clegg // If either function is missing a signature (this happend for bitcode 150d506b0a4SSam Clegg // symbols) then assume they match. Any mismatch will be reported later 151d506b0a4SSam Clegg // when the LTO objects are added. 152136d27abSRui Ueyama if (!newSig || !oldSig) 1536540e570SSam Clegg return true; 154cefbf9acSSam Clegg 155136d27abSRui Ueyama return *newSig == *oldSig; 156e3498ec5SRui Ueyama } 157e3498ec5SRui Ueyama 158136d27abSRui Ueyama static void checkGlobalType(const Symbol *existing, const InputFile *file, 159136d27abSRui Ueyama const WasmGlobalType *newType) { 160136d27abSRui Ueyama if (!isa<GlobalSymbol>(existing)) { 161136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL); 162b8621596SSam Clegg return; 163b8621596SSam Clegg } 164b8621596SSam Clegg 165136d27abSRui Ueyama const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType(); 166136d27abSRui Ueyama if (*newType != *oldType) { 167136d27abSRui Ueyama error("Global type mismatch: " + existing->getName() + "\n>>> defined as " + 168136d27abSRui Ueyama toString(*oldType) + " in " + toString(existing->getFile()) + 169136d27abSRui Ueyama "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 170c94d393aSSam Clegg } 17124b3dcd4SSam Clegg } 17224b3dcd4SSam Clegg 173136d27abSRui Ueyama static void checkEventType(const Symbol *existing, const InputFile *file, 174136d27abSRui Ueyama const WasmEventType *newType, 175136d27abSRui Ueyama const WasmSignature *newSig) { 176136d27abSRui Ueyama auto existingEvent = dyn_cast<EventSymbol>(existing); 177136d27abSRui Ueyama if (!isa<EventSymbol>(existing)) { 178136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT); 179e915a71fSHeejin Ahn return; 180e915a71fSHeejin Ahn } 181e915a71fSHeejin Ahn 182136d27abSRui Ueyama const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType(); 183136d27abSRui Ueyama const WasmSignature *oldSig = existingEvent->signature; 184136d27abSRui Ueyama if (newType->Attribute != oldType->Attribute) 185136d27abSRui Ueyama error("Event type mismatch: " + existing->getName() + "\n>>> defined as " + 186136d27abSRui Ueyama toString(*oldType) + " in " + toString(existing->getFile()) + 187136d27abSRui Ueyama "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 188136d27abSRui Ueyama if (*newSig != *oldSig) 189136d27abSRui Ueyama warn("Event signature mismatch: " + existing->getName() + 190136d27abSRui Ueyama "\n>>> defined as " + toString(*oldSig) + " in " + 191136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined as " + 192136d27abSRui Ueyama toString(*newSig) + " in " + toString(file)); 193e915a71fSHeejin Ahn } 194e915a71fSHeejin Ahn 19553e3b81fSAndy Wingo static void checkTableType(const Symbol *existing, const InputFile *file, 19653e3b81fSAndy Wingo const WasmTableType *newType) { 19753e3b81fSAndy Wingo if (!isa<TableSymbol>(existing)) { 19853e3b81fSAndy Wingo reportTypeError(existing, file, WASM_SYMBOL_TYPE_TABLE); 19953e3b81fSAndy Wingo return; 20053e3b81fSAndy Wingo } 20153e3b81fSAndy Wingo 20253e3b81fSAndy Wingo const WasmTableType *oldType = cast<TableSymbol>(existing)->getTableType(); 20353e3b81fSAndy Wingo if (newType->ElemType != oldType->ElemType) { 20453e3b81fSAndy Wingo error("Table type mismatch: " + existing->getName() + "\n>>> defined as " + 20553e3b81fSAndy Wingo toString(*oldType) + " in " + toString(existing->getFile()) + 20653e3b81fSAndy Wingo "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 20753e3b81fSAndy Wingo } 20853e3b81fSAndy Wingo // FIXME: No assertions currently on the limits. 20953e3b81fSAndy Wingo } 21053e3b81fSAndy Wingo 211136d27abSRui Ueyama static void checkDataType(const Symbol *existing, const InputFile *file) { 212136d27abSRui Ueyama if (!isa<DataSymbol>(existing)) 213136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA); 214e3498ec5SRui Ueyama } 215e3498ec5SRui Ueyama 216136d27abSRui Ueyama DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, 217136d27abSRui Ueyama uint32_t flags, 218136d27abSRui Ueyama InputFunction *function) { 219136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); 220136d27abSRui Ueyama assert(!find(name)); 221136d27abSRui Ueyama syntheticFunctions.emplace_back(function); 222136d27abSRui Ueyama return replaceSymbol<DefinedFunction>(insertName(name).first, name, 223136d27abSRui Ueyama flags, nullptr, function); 22450686856SSam Clegg } 22550686856SSam Clegg 22629a3056bSSam Clegg // Adds an optional, linker generated, data symbol. The symbol will only be 2277ae3d335SKazuaki Ishizaki // added if there is an undefine reference to it, or if it is explicitly 2287ae3d335SKazuaki Ishizaki // exported via the --export flag. Otherwise we don't add the symbol and return 2297ae3d335SKazuaki Ishizaki // nullptr. 230caa0db13SSam Clegg DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, 231582fd474SWouter van Oortmerssen uint64_t value) { 232136d27abSRui Ueyama Symbol *s = find(name); 233136d27abSRui Ueyama if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0)) 234136d27abSRui Ueyama s = insertName(name).first; 235136d27abSRui Ueyama else if (!s || s->isDefined()) 2364bce63a0SSam Clegg return nullptr; 237136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n"); 238caa0db13SSam Clegg auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN); 239136d27abSRui Ueyama rtn->setVirtualAddress(value); 240136d27abSRui Ueyama rtn->referenced = true; 2414bce63a0SSam Clegg return rtn; 2424bce63a0SSam Clegg } 2434bce63a0SSam Clegg 244136d27abSRui Ueyama DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, 245136d27abSRui Ueyama uint32_t flags) { 246136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); 247136d27abSRui Ueyama assert(!find(name)); 248136d27abSRui Ueyama return replaceSymbol<DefinedData>(insertName(name).first, name, flags); 249c94d393aSSam Clegg } 250c94d393aSSam Clegg 251136d27abSRui Ueyama DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, 252136d27abSRui Ueyama InputGlobal *global) { 253136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global 254e7245b42SNicola Zaghen << "\n"); 255136d27abSRui Ueyama assert(!find(name)); 256136d27abSRui Ueyama syntheticGlobals.emplace_back(global); 257136d27abSRui Ueyama return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags, 258136d27abSRui Ueyama nullptr, global); 25993102974SSam Clegg } 26093102974SSam Clegg 26129a3056bSSam Clegg DefinedGlobal *SymbolTable::addOptionalGlobalSymbols(StringRef name, 26229a3056bSSam Clegg uint32_t flags, 26329a3056bSSam Clegg InputGlobal *global) { 26429a3056bSSam Clegg LLVM_DEBUG(dbgs() << "addOptionalGlobalSymbols: " << name << " -> " << global 26529a3056bSSam Clegg << "\n"); 26629a3056bSSam Clegg Symbol *s = find(name); 26729a3056bSSam Clegg if (!s || s->isDefined()) 26829a3056bSSam Clegg return nullptr; 26929a3056bSSam Clegg syntheticGlobals.emplace_back(global); 27029a3056bSSam Clegg return replaceSymbol<DefinedGlobal>(s, name, flags, nullptr, global); 27129a3056bSSam Clegg } 27229a3056bSSam Clegg 273*63393828SAndy Wingo DefinedTable *SymbolTable::addSyntheticTable(StringRef name, uint32_t flags, 274*63393828SAndy Wingo InputTable *table) { 275*63393828SAndy Wingo LLVM_DEBUG(dbgs() << "addSyntheticTable: " << name << " -> " << table 276*63393828SAndy Wingo << "\n"); 277*63393828SAndy Wingo Symbol *s = find(name); 278*63393828SAndy Wingo assert(!s || s->isUndefined()); 279*63393828SAndy Wingo if (!s) 280*63393828SAndy Wingo s = insertName(name).first; 281*63393828SAndy Wingo syntheticTables.emplace_back(table); 282*63393828SAndy Wingo return replaceSymbol<DefinedTable>(s, name, flags, nullptr, table); 283*63393828SAndy Wingo } 284*63393828SAndy Wingo 285136d27abSRui Ueyama static bool shouldReplace(const Symbol *existing, InputFile *newFile, 286136d27abSRui Ueyama uint32_t newFlags) { 287c03c9040SRui Ueyama // If existing symbol is undefined, replace it. 288136d27abSRui Ueyama if (!existing->isDefined()) { 289e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 290136d27abSRui Ueyama << existing->getName() << "\n"); 291c03c9040SRui Ueyama return true; 292c03c9040SRui Ueyama } 293c03c9040SRui Ueyama 294c03c9040SRui Ueyama // Now we have two defined symbols. If the new one is weak, we can ignore it. 295136d27abSRui Ueyama if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 296e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 297c03c9040SRui Ueyama return false; 298c03c9040SRui Ueyama } 299c03c9040SRui Ueyama 300c03c9040SRui Ueyama // If the existing symbol is weak, we should replace it. 301136d27abSRui Ueyama if (existing->isWeak()) { 302e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 303c03c9040SRui Ueyama return true; 304c03c9040SRui Ueyama } 305c03c9040SRui Ueyama 306c03c9040SRui Ueyama // Neither symbol is week. They conflict. 307136d27abSRui Ueyama error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + 308136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined in " + 309136d27abSRui Ueyama toString(newFile)); 310c03c9040SRui Ueyama return true; 311b8621596SSam Clegg } 31293e559b1SSam Clegg 313136d27abSRui Ueyama Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags, 314136d27abSRui Ueyama InputFile *file, 315136d27abSRui Ueyama InputFunction *function) { 316136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " [" 317136d27abSRui Ueyama << (function ? toString(function->signature) : "none") 3188b0b48f3SSam Clegg << "]\n"); 319136d27abSRui Ueyama Symbol *s; 320136d27abSRui Ueyama bool wasInserted; 321136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 322c729c1b4SSam Clegg 323136d27abSRui Ueyama auto replaceSym = [&](Symbol *sym) { 3247c5fcb35SKazuaki Ishizaki // If the new defined function doesn't have signature (i.e. bitcode 3256540e570SSam Clegg // functions) but the old symbol does, then preserve the old signature 326136d27abSRui Ueyama const WasmSignature *oldSig = s->getSignature(); 327136d27abSRui Ueyama auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function); 328136d27abSRui Ueyama if (!newSym->signature) 329136d27abSRui Ueyama newSym->signature = oldSig; 3306540e570SSam Clegg }; 3316540e570SSam Clegg 332136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 333136d27abSRui Ueyama replaceSym(s); 334136d27abSRui Ueyama return s; 335e3498ec5SRui Ueyama } 336e3498ec5SRui Ueyama 337136d27abSRui Ueyama auto existingFunction = dyn_cast<FunctionSymbol>(s); 338136d27abSRui Ueyama if (!existingFunction) { 339136d27abSRui Ueyama reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 340136d27abSRui Ueyama return s; 3418b0b48f3SSam Clegg } 3426540e570SSam Clegg 343136d27abSRui Ueyama bool checkSig = true; 344136d27abSRui Ueyama if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) 345136d27abSRui Ueyama checkSig = ud->isCalledDirectly; 34659f959ffSSam Clegg 347136d27abSRui Ueyama if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) { 348136d27abSRui Ueyama Symbol* variant; 349136d27abSRui Ueyama if (getFunctionVariant(s, &function->signature, file, &variant)) 3506540e570SSam Clegg // New variant, always replace 351136d27abSRui Ueyama replaceSym(variant); 352136d27abSRui Ueyama else if (shouldReplace(s, file, flags)) 3536540e570SSam Clegg // Variant already exists, replace it after checking shouldReplace 354136d27abSRui Ueyama replaceSym(variant); 3556540e570SSam Clegg 3566540e570SSam Clegg // This variant we found take the place in the symbol table as the primary 3576540e570SSam Clegg // variant. 358136d27abSRui Ueyama replace(name, variant); 359136d27abSRui Ueyama return variant; 3606540e570SSam Clegg } 3616540e570SSam Clegg 3626540e570SSam Clegg // Existing function with matching signature. 363136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 364136d27abSRui Ueyama replaceSym(s); 3656540e570SSam Clegg 366136d27abSRui Ueyama return s; 36793e559b1SSam Clegg } 36893e559b1SSam Clegg 369136d27abSRui Ueyama Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, 370136d27abSRui Ueyama InputFile *file, InputSegment *segment, 3713b29376eSWouter van Oortmerssen uint64_t address, uint64_t size) { 372136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address 373e7245b42SNicola Zaghen << "\n"); 374136d27abSRui Ueyama Symbol *s; 375136d27abSRui Ueyama bool wasInserted; 376136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 377c729c1b4SSam Clegg 378136d27abSRui Ueyama auto replaceSym = [&]() { 379136d27abSRui Ueyama replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size); 3806540e570SSam Clegg }; 3816540e570SSam Clegg 382136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 383136d27abSRui Ueyama replaceSym(); 384136d27abSRui Ueyama return s; 385e3498ec5SRui Ueyama } 386e3498ec5SRui Ueyama 387136d27abSRui Ueyama checkDataType(s, file); 388e3498ec5SRui Ueyama 389136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 390136d27abSRui Ueyama replaceSym(); 391136d27abSRui Ueyama return s; 392c94d393aSSam Clegg } 393c94d393aSSam Clegg 394136d27abSRui Ueyama Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags, 395136d27abSRui Ueyama InputFile *file, InputGlobal *global) { 396136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n"); 3974c2cbfe6SSam Clegg 398136d27abSRui Ueyama Symbol *s; 399136d27abSRui Ueyama bool wasInserted; 400136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 401c729c1b4SSam Clegg 402136d27abSRui Ueyama auto replaceSym = [&]() { 403136d27abSRui Ueyama replaceSymbol<DefinedGlobal>(s, name, flags, file, global); 4046540e570SSam Clegg }; 4056540e570SSam Clegg 406136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 407136d27abSRui Ueyama replaceSym(); 408136d27abSRui Ueyama return s; 40993102974SSam Clegg } 41093102974SSam Clegg 411136d27abSRui Ueyama checkGlobalType(s, file, &global->getType()); 412e3498ec5SRui Ueyama 413136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 414136d27abSRui Ueyama replaceSym(); 415136d27abSRui Ueyama return s; 416e3498ec5SRui Ueyama } 417e3498ec5SRui Ueyama 418136d27abSRui Ueyama Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags, 419136d27abSRui Ueyama InputFile *file, InputEvent *event) { 420136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n"); 421e915a71fSHeejin Ahn 422136d27abSRui Ueyama Symbol *s; 423136d27abSRui Ueyama bool wasInserted; 424136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 425e915a71fSHeejin Ahn 426136d27abSRui Ueyama auto replaceSym = [&]() { 427136d27abSRui Ueyama replaceSymbol<DefinedEvent>(s, name, flags, file, event); 4286540e570SSam Clegg }; 4296540e570SSam Clegg 430136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 431136d27abSRui Ueyama replaceSym(); 432136d27abSRui Ueyama return s; 433e915a71fSHeejin Ahn } 434e915a71fSHeejin Ahn 435136d27abSRui Ueyama checkEventType(s, file, &event->getType(), &event->signature); 436e915a71fSHeejin Ahn 437136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 438136d27abSRui Ueyama replaceSym(); 439136d27abSRui Ueyama return s; 440e915a71fSHeejin Ahn } 441e915a71fSHeejin Ahn 44253e3b81fSAndy Wingo Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags, 44353e3b81fSAndy Wingo InputFile *file, InputTable *table) { 44453e3b81fSAndy Wingo LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n"); 44553e3b81fSAndy Wingo 44653e3b81fSAndy Wingo Symbol *s; 44753e3b81fSAndy Wingo bool wasInserted; 44853e3b81fSAndy Wingo std::tie(s, wasInserted) = insert(name, file); 44953e3b81fSAndy Wingo 45053e3b81fSAndy Wingo auto replaceSym = [&]() { 45153e3b81fSAndy Wingo replaceSymbol<DefinedTable>(s, name, flags, file, table); 45253e3b81fSAndy Wingo }; 45353e3b81fSAndy Wingo 45453e3b81fSAndy Wingo if (wasInserted || s->isLazy()) { 45553e3b81fSAndy Wingo replaceSym(); 45653e3b81fSAndy Wingo return s; 45753e3b81fSAndy Wingo } 45853e3b81fSAndy Wingo 45953e3b81fSAndy Wingo checkTableType(s, file, &table->getType()); 46053e3b81fSAndy Wingo 46153e3b81fSAndy Wingo if (shouldReplace(s, file, flags)) 46253e3b81fSAndy Wingo replaceSym(); 46353e3b81fSAndy Wingo return s; 46453e3b81fSAndy Wingo } 46553e3b81fSAndy Wingo 46667b05584SSam Clegg // This function get called when an undefined symbol is added, and there is 46767b05584SSam Clegg // already an existing one in the symbols table. In this case we check that 46867b05584SSam Clegg // custom 'import-module' and 'import-field' symbol attributes agree. 4697ae3d335SKazuaki Ishizaki // With LTO these attributes are not available when the bitcode is read and only 47067b05584SSam Clegg // become available when the LTO object is read. In this case we silently 47167b05584SSam Clegg // replace the empty attributes with the valid ones. 47267b05584SSam Clegg template <typename T> 473bd481277SSam Clegg static void setImportAttributes(T *existing, Optional<StringRef> importName, 474bd481277SSam Clegg Optional<StringRef> importModule, 475a57f1a54SSam Clegg uint32_t flags, InputFile *file) { 476bd481277SSam Clegg if (importName) { 477bd481277SSam Clegg if (!existing->importName) 47867b05584SSam Clegg existing->importName = importName; 47967b05584SSam Clegg if (existing->importName != importName) 48067b05584SSam Clegg error("import name mismatch for symbol: " + toString(*existing) + 481bd481277SSam Clegg "\n>>> defined as " + *existing->importName + " in " + 482bd481277SSam Clegg toString(existing->getFile()) + "\n>>> defined as " + *importName + 48367b05584SSam Clegg " in " + toString(file)); 48467b05584SSam Clegg } 48567b05584SSam Clegg 486bd481277SSam Clegg if (importModule) { 487bd481277SSam Clegg if (!existing->importModule) 48867b05584SSam Clegg existing->importModule = importModule; 48967b05584SSam Clegg if (existing->importModule != importModule) 49067b05584SSam Clegg error("import module mismatch for symbol: " + toString(*existing) + 491bd481277SSam Clegg "\n>>> defined as " + *existing->importModule + " in " + 492bd481277SSam Clegg toString(existing->getFile()) + "\n>>> defined as " + 493bd481277SSam Clegg *importModule + " in " + toString(file)); 49467b05584SSam Clegg } 495a57f1a54SSam Clegg 496a57f1a54SSam Clegg // Update symbol binding, if the existing symbol is weak 497a57f1a54SSam Clegg uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK; 498a57f1a54SSam Clegg if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) { 499a57f1a54SSam Clegg existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding; 500a57f1a54SSam Clegg } 50167b05584SSam Clegg } 50267b05584SSam Clegg 503bd481277SSam Clegg Symbol *SymbolTable::addUndefinedFunction(StringRef name, 504bd481277SSam Clegg Optional<StringRef> importName, 505bd481277SSam Clegg Optional<StringRef> importModule, 506136d27abSRui Ueyama uint32_t flags, InputFile *file, 507136d27abSRui Ueyama const WasmSignature *sig, 508136d27abSRui Ueyama bool isCalledDirectly) { 509136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" 510136d27abSRui Ueyama << (sig ? toString(*sig) : "none") 511a57f1a54SSam Clegg << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x" 512a57f1a54SSam Clegg << utohexstr(flags) << "\n"); 513f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 514c03c9040SRui Ueyama 515136d27abSRui Ueyama Symbol *s; 516136d27abSRui Ueyama bool wasInserted; 517136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 518136d27abSRui Ueyama if (s->traced) 519136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 520c729c1b4SSam Clegg 521136d27abSRui Ueyama auto replaceSym = [&]() { 522136d27abSRui Ueyama replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags, 523136d27abSRui Ueyama file, sig, isCalledDirectly); 5246540e570SSam Clegg }; 5256540e570SSam Clegg 526b34ec596SSam Clegg if (wasInserted) { 527136d27abSRui Ueyama replaceSym(); 528b34ec596SSam Clegg } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 529b34ec596SSam Clegg if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 530b34ec596SSam Clegg lazy->setWeak(); 531b34ec596SSam Clegg lazy->signature = sig; 532b34ec596SSam Clegg } else { 533136d27abSRui Ueyama lazy->fetch(); 534b34ec596SSam Clegg } 535b34ec596SSam Clegg } else { 536136d27abSRui Ueyama auto existingFunction = dyn_cast<FunctionSymbol>(s); 537136d27abSRui Ueyama if (!existingFunction) { 538136d27abSRui Ueyama reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 539136d27abSRui Ueyama return s; 5406540e570SSam Clegg } 541136d27abSRui Ueyama if (!existingFunction->signature && sig) 542136d27abSRui Ueyama existingFunction->signature = sig; 543a57f1a54SSam Clegg auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction); 544fecfc592SSam Clegg if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { 545a57f1a54SSam Clegg // If the existing undefined functions is not called directly then let 546fecfc592SSam Clegg // this one take precedence. Otherwise the existing function is either 547a57f1a54SSam Clegg // directly called or defined, in which case we need a function variant. 548fecfc592SSam Clegg if (existingUndefined && !existingUndefined->isCalledDirectly) 549136d27abSRui Ueyama replaceSym(); 550fecfc592SSam Clegg else if (getFunctionVariant(s, sig, file, &s)) 551fecfc592SSam Clegg replaceSym(); 552fecfc592SSam Clegg } 55367b05584SSam Clegg if (existingUndefined) 554a57f1a54SSam Clegg setImportAttributes(existingUndefined, importName, importModule, flags, 555a57f1a54SSam Clegg file); 5566540e570SSam Clegg } 557cefbf9acSSam Clegg 558136d27abSRui Ueyama return s; 559c03c9040SRui Ueyama } 560c03c9040SRui Ueyama 561136d27abSRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, 562136d27abSRui Ueyama InputFile *file) { 563136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); 564f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 56593102974SSam Clegg 566136d27abSRui Ueyama Symbol *s; 567136d27abSRui Ueyama bool wasInserted; 568136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 569136d27abSRui Ueyama if (s->traced) 570136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 571f989a92dSSam Clegg 572b34ec596SSam Clegg if (wasInserted) { 573136d27abSRui Ueyama replaceSymbol<UndefinedData>(s, name, flags, file); 574b34ec596SSam Clegg } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 575b34ec596SSam Clegg if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) 576b34ec596SSam Clegg lazy->setWeak(); 577b34ec596SSam Clegg else 578136d27abSRui Ueyama lazy->fetch(); 579b34ec596SSam Clegg } else if (s->isDefined()) { 580136d27abSRui Ueyama checkDataType(s, file); 581b34ec596SSam Clegg } 582136d27abSRui Ueyama return s; 583c94d393aSSam Clegg } 584c94d393aSSam Clegg 585bd481277SSam Clegg Symbol *SymbolTable::addUndefinedGlobal(StringRef name, 586bd481277SSam Clegg Optional<StringRef> importName, 587bd481277SSam Clegg Optional<StringRef> importModule, 588bd481277SSam Clegg uint32_t flags, InputFile *file, 589136d27abSRui Ueyama const WasmGlobalType *type) { 590136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); 591f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 592e3498ec5SRui Ueyama 593136d27abSRui Ueyama Symbol *s; 594136d27abSRui Ueyama bool wasInserted; 595136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 596136d27abSRui Ueyama if (s->traced) 597136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 598c729c1b4SSam Clegg 599136d27abSRui Ueyama if (wasInserted) 600136d27abSRui Ueyama replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, 601136d27abSRui Ueyama file, type); 602136d27abSRui Ueyama else if (auto *lazy = dyn_cast<LazySymbol>(s)) 603136d27abSRui Ueyama lazy->fetch(); 604136d27abSRui Ueyama else if (s->isDefined()) 605136d27abSRui Ueyama checkGlobalType(s, file, type); 606136d27abSRui Ueyama return s; 607e3498ec5SRui Ueyama } 608e3498ec5SRui Ueyama 60953e3b81fSAndy Wingo Symbol *SymbolTable::addUndefinedTable(StringRef name, 61053e3b81fSAndy Wingo Optional<StringRef> importName, 61153e3b81fSAndy Wingo Optional<StringRef> importModule, 61253e3b81fSAndy Wingo uint32_t flags, InputFile *file, 61353e3b81fSAndy Wingo const WasmTableType *type) { 61453e3b81fSAndy Wingo LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n"); 61553e3b81fSAndy Wingo assert(flags & WASM_SYMBOL_UNDEFINED); 61653e3b81fSAndy Wingo 61753e3b81fSAndy Wingo Symbol *s; 61853e3b81fSAndy Wingo bool wasInserted; 61953e3b81fSAndy Wingo std::tie(s, wasInserted) = insert(name, file); 62053e3b81fSAndy Wingo if (s->traced) 62153e3b81fSAndy Wingo printTraceSymbolUndefined(name, file); 62253e3b81fSAndy Wingo 62353e3b81fSAndy Wingo if (wasInserted) 62453e3b81fSAndy Wingo replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags, 62553e3b81fSAndy Wingo file, type); 62653e3b81fSAndy Wingo else if (auto *lazy = dyn_cast<LazySymbol>(s)) 62753e3b81fSAndy Wingo lazy->fetch(); 62853e3b81fSAndy Wingo else if (s->isDefined()) 62953e3b81fSAndy Wingo checkTableType(s, file, type); 63053e3b81fSAndy Wingo return s; 63153e3b81fSAndy Wingo } 63253e3b81fSAndy Wingo 633136d27abSRui Ueyama void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) { 634136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n"); 635136d27abSRui Ueyama StringRef name = sym->getName(); 636c03c9040SRui Ueyama 637136d27abSRui Ueyama Symbol *s; 638136d27abSRui Ueyama bool wasInserted; 639136d27abSRui Ueyama std::tie(s, wasInserted) = insertName(name); 640c03c9040SRui Ueyama 641136d27abSRui Ueyama if (wasInserted) { 642136d27abSRui Ueyama replaceSymbol<LazySymbol>(s, name, 0, file, *sym); 643c03c9040SRui Ueyama return; 644c03c9040SRui Ueyama } 645c03c9040SRui Ueyama 646136d27abSRui Ueyama if (!s->isUndefined()) 64737b4ee52SSam Clegg return; 64837b4ee52SSam Clegg 64937b4ee52SSam Clegg // The existing symbol is undefined, load a new one from the archive, 6507ae3d335SKazuaki Ishizaki // unless the existing symbol is weak in which case replace the undefined 65137b4ee52SSam Clegg // symbols with a LazySymbol. 652136d27abSRui Ueyama if (s->isWeak()) { 653136d27abSRui Ueyama const WasmSignature *oldSig = nullptr; 65437b4ee52SSam Clegg // In the case of an UndefinedFunction we need to preserve the expected 65537b4ee52SSam Clegg // signature. 656136d27abSRui Ueyama if (auto *f = dyn_cast<UndefinedFunction>(s)) 657136d27abSRui Ueyama oldSig = f->signature; 65837b4ee52SSam Clegg LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 659136d27abSRui Ueyama auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, 660136d27abSRui Ueyama file, *sym); 661136d27abSRui Ueyama newSym->signature = oldSig; 66237b4ee52SSam Clegg return; 66337b4ee52SSam Clegg } 66437b4ee52SSam Clegg 665e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 666136d27abSRui Ueyama file->addMember(sym); 667c94d393aSSam Clegg } 668e0f6fcd0SSam Clegg 669136d27abSRui Ueyama bool SymbolTable::addComdat(StringRef name) { 670136d27abSRui Ueyama return comdatGroups.insert(CachedHashStringRef(name)).second; 671e0f6fcd0SSam Clegg } 6721f3f774fSSam Clegg 6736540e570SSam Clegg // The new signature doesn't match. Create a variant to the symbol with the 6746540e570SSam Clegg // signature encoded in the name and return that instead. These symbols are 6756540e570SSam Clegg // then unified later in handleSymbolVariants. 676136d27abSRui Ueyama bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, 677136d27abSRui Ueyama const InputFile *file, Symbol **out) { 678136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " 679136d27abSRui Ueyama << " " << toString(*sig) << "\n"); 680136d27abSRui Ueyama Symbol *variant = nullptr; 6816540e570SSam Clegg 6826540e570SSam Clegg // Linear search through symbol variants. Should never be more than two 6836540e570SSam Clegg // or three entries here. 684136d27abSRui Ueyama auto &variants = symVariants[CachedHashStringRef(sym->getName())]; 685136d27abSRui Ueyama if (variants.empty()) 686136d27abSRui Ueyama variants.push_back(sym); 6876540e570SSam Clegg 688136d27abSRui Ueyama for (Symbol* v : variants) { 689136d27abSRui Ueyama if (*v->getSignature() == *sig) { 690136d27abSRui Ueyama variant = v; 6916540e570SSam Clegg break; 6926540e570SSam Clegg } 6936540e570SSam Clegg } 6946540e570SSam Clegg 695136d27abSRui Ueyama bool wasAdded = !variant; 696136d27abSRui Ueyama if (wasAdded) { 6976540e570SSam Clegg // Create a new variant; 6986540e570SSam Clegg LLVM_DEBUG(dbgs() << "added new variant\n"); 699136d27abSRui Ueyama variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 700064e9907SSam Clegg variant->isUsedInRegularObj = 701064e9907SSam Clegg !file || file->kind() == InputFile::ObjectKind; 702064e9907SSam Clegg variant->canInline = true; 703064e9907SSam Clegg variant->traced = false; 704064e9907SSam Clegg variant->forceExport = false; 705136d27abSRui Ueyama variants.push_back(variant); 7066540e570SSam Clegg } else { 707136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); 708136d27abSRui Ueyama assert(*variant->getSignature() == *sig); 7096540e570SSam Clegg } 7106540e570SSam Clegg 711136d27abSRui Ueyama *out = variant; 712136d27abSRui Ueyama return wasAdded; 7136540e570SSam Clegg } 7146540e570SSam Clegg 7151f3f774fSSam Clegg // Set a flag for --trace-symbol so that we can print out a log message 7161f3f774fSSam Clegg // if a new symbol with the same name is inserted into the symbol table. 717136d27abSRui Ueyama void SymbolTable::trace(StringRef name) { 718136d27abSRui Ueyama symMap.insert({CachedHashStringRef(name), -1}); 7191f3f774fSSam Clegg } 720230dc11dSSam Clegg 721136d27abSRui Ueyama void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { 722a5ca34e6SSam Clegg // Swap symbols as instructed by -wrap. 723136d27abSRui Ueyama int &origIdx = symMap[CachedHashStringRef(sym->getName())]; 724136d27abSRui Ueyama int &realIdx= symMap[CachedHashStringRef(real->getName())]; 725136d27abSRui Ueyama int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; 726136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); 727a5ca34e6SSam Clegg 728a5ca34e6SSam Clegg // Anyone looking up __real symbols should get the original 729136d27abSRui Ueyama realIdx = origIdx; 730a5ca34e6SSam Clegg // Anyone looking up the original should get the __wrap symbol 731136d27abSRui Ueyama origIdx = wrapIdx; 732a5ca34e6SSam Clegg } 733a5ca34e6SSam Clegg 734136d27abSRui Ueyama static const uint8_t unreachableFn[] = { 735230dc11dSSam Clegg 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 736230dc11dSSam Clegg 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 737230dc11dSSam Clegg }; 738230dc11dSSam Clegg 739230dc11dSSam Clegg // Replace the given symbol body with an unreachable function. 740230dc11dSSam Clegg // This is used by handleWeakUndefines in order to generate a callable 7416540e570SSam Clegg // equivalent of an undefined function and also handleSymbolVariants for 7426540e570SSam Clegg // undefined functions that don't match the signature of the definition. 743136d27abSRui Ueyama InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, 744136d27abSRui Ueyama const WasmSignature &sig, 745136d27abSRui Ueyama StringRef debugName) { 746136d27abSRui Ueyama auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); 747136d27abSRui Ueyama func->setBody(unreachableFn); 748136d27abSRui Ueyama syntheticFunctions.emplace_back(func); 7494b8e2d8eSSam Clegg // Mark new symbols as local. For relocatable output we don't want them 7504b8e2d8eSSam Clegg // to be exported outside the object file. 7514b8e2d8eSSam Clegg replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL, 7524b8e2d8eSSam Clegg nullptr, func); 75348ddf5e1SSam Clegg // Ensure the stub function doesn't get a table entry. Its address 75448ddf5e1SSam Clegg // should always compare equal to the null pointer. 75548ddf5e1SSam Clegg sym->isStub = true; 756136d27abSRui Ueyama return func; 757230dc11dSSam Clegg } 758230dc11dSSam Clegg 759206884bfSSam Clegg void SymbolTable::replaceWithUndefined(Symbol *sym) { 760206884bfSSam Clegg // Add a synthetic dummy for weak undefined functions. These dummies will 761206884bfSSam Clegg // be GC'd if not used as the target of any "call" instructions. 762206884bfSSam Clegg StringRef debugName = saver.save("undefined_weak:" + toString(*sym)); 763206884bfSSam Clegg replaceWithUnreachable(sym, *sym->getSignature(), debugName); 764206884bfSSam Clegg // Hide our dummy to prevent export. 765206884bfSSam Clegg sym->setHidden(true); 766206884bfSSam Clegg } 767206884bfSSam Clegg 768230dc11dSSam Clegg // For weak undefined functions, there may be "call" instructions that reference 769230dc11dSSam Clegg // the symbol. In this case, we need to synthesise a dummy/stub function that 770230dc11dSSam Clegg // will abort at runtime, so that relocations can still provided an operand to 771230dc11dSSam Clegg // the call instruction that passes Wasm validation. 772230dc11dSSam Clegg void SymbolTable::handleWeakUndefines() { 773136d27abSRui Ueyama for (Symbol *sym : getSymbols()) { 774206884bfSSam Clegg if (sym->isUndefWeak()) { 775206884bfSSam Clegg if (sym->getSignature()) { 776206884bfSSam Clegg replaceWithUndefined(sym); 777206884bfSSam Clegg } else { 778206884bfSSam Clegg // It is possible for undefined functions not to have a signature (eg. 779206884bfSSam Clegg // if added via "--undefined"), but weak undefined ones do have a 780206884bfSSam Clegg // signature. Lazy symbols may not be functions and therefore Sig can 781206884bfSSam Clegg // still be null in some circumstance. 782136d27abSRui Ueyama assert(!isa<FunctionSymbol>(sym)); 783206884bfSSam Clegg } 784206884bfSSam Clegg } 785206884bfSSam Clegg } 7866540e570SSam Clegg } 787230dc11dSSam Clegg 788206884bfSSam Clegg DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) { 789206884bfSSam Clegg if (stubFunctions.count(sig)) 790206884bfSSam Clegg return stubFunctions[sig]; 791206884bfSSam Clegg LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n"); 792206884bfSSam Clegg auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>()); 793206884bfSSam Clegg sym->isUsedInRegularObj = true; 794206884bfSSam Clegg sym->canInline = true; 795206884bfSSam Clegg sym->traced = false; 796206884bfSSam Clegg sym->forceExport = false; 797206884bfSSam Clegg sym->signature = &sig; 798206884bfSSam Clegg replaceSymbol<DefinedFunction>( 799206884bfSSam Clegg sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr); 800206884bfSSam Clegg replaceWithUnreachable(sym, sig, "undefined_stub"); 801206884bfSSam Clegg stubFunctions[sig] = sym; 802206884bfSSam Clegg return sym; 803230dc11dSSam Clegg } 8046540e570SSam Clegg 805136d27abSRui Ueyama static void reportFunctionSignatureMismatch(StringRef symName, 806136d27abSRui Ueyama FunctionSymbol *a, 807136d27abSRui Ueyama FunctionSymbol *b, bool isError) { 808136d27abSRui Ueyama std::string msg = ("function signature mismatch: " + symName + 809136d27abSRui Ueyama "\n>>> defined as " + toString(*a->signature) + " in " + 810136d27abSRui Ueyama toString(a->getFile()) + "\n>>> defined as " + 811136d27abSRui Ueyama toString(*b->signature) + " in " + toString(b->getFile())) 8126540e570SSam Clegg .str(); 813136d27abSRui Ueyama if (isError) 8146540e570SSam Clegg error(msg); 8156540e570SSam Clegg else 8166540e570SSam Clegg warn(msg); 8176540e570SSam Clegg } 8186540e570SSam Clegg 8196540e570SSam Clegg // Remove any variant symbols that were created due to function signature 8206540e570SSam Clegg // mismatches. 8216540e570SSam Clegg void SymbolTable::handleSymbolVariants() { 822136d27abSRui Ueyama for (auto pair : symVariants) { 8236540e570SSam Clegg // Push the initial symbol onto the list of variants. 824136d27abSRui Ueyama StringRef symName = pair.first.val(); 825136d27abSRui Ueyama std::vector<Symbol *> &variants = pair.second; 8266540e570SSam Clegg 8276540e570SSam Clegg #ifndef NDEBUG 828136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() 829136d27abSRui Ueyama << ") variants: " << symName << "\n"); 830136d27abSRui Ueyama for (auto *s: variants) { 831136d27abSRui Ueyama auto *f = cast<FunctionSymbol>(s); 832136d27abSRui Ueyama LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " 833136d27abSRui Ueyama << toString(*f->signature) << "\n"); 8346540e570SSam Clegg } 8356540e570SSam Clegg #endif 8366540e570SSam Clegg 8376540e570SSam Clegg // Find the one definition. 838136d27abSRui Ueyama DefinedFunction *defined = nullptr; 839136d27abSRui Ueyama for (auto *symbol : variants) { 840136d27abSRui Ueyama if (auto f = dyn_cast<DefinedFunction>(symbol)) { 841136d27abSRui Ueyama defined = f; 8426540e570SSam Clegg break; 8436540e570SSam Clegg } 8446540e570SSam Clegg } 8456540e570SSam Clegg 8466540e570SSam Clegg // If there are no definitions, and the undefined symbols disagree on 8476540e570SSam Clegg // the signature, there is not we can do since we don't know which one 8486540e570SSam Clegg // to use as the signature on the import. 849136d27abSRui Ueyama if (!defined) { 850136d27abSRui Ueyama reportFunctionSignatureMismatch(symName, 851136d27abSRui Ueyama cast<FunctionSymbol>(variants[0]), 852136d27abSRui Ueyama cast<FunctionSymbol>(variants[1]), true); 8536540e570SSam Clegg return; 8546540e570SSam Clegg } 8556540e570SSam Clegg 856136d27abSRui Ueyama for (auto *symbol : variants) { 857136d27abSRui Ueyama if (symbol != defined) { 858136d27abSRui Ueyama auto *f = cast<FunctionSymbol>(symbol); 859136d27abSRui Ueyama reportFunctionSignatureMismatch(symName, f, defined, false); 86051b521c0SSam Clegg StringRef debugName = saver.save("signature_mismatch:" + toString(*f)); 861136d27abSRui Ueyama replaceWithUnreachable(f, *f->signature, debugName); 8626540e570SSam Clegg } 8636540e570SSam Clegg } 8646540e570SSam Clegg } 8656540e570SSam Clegg } 86633c59abfSFangrui Song 86733c59abfSFangrui Song } // namespace wasm 86833c59abfSFangrui Song } // namespace lld 869