1c94d393aSSam Clegg //===- SymbolTable.cpp ----------------------------------------------------===// 2c94d393aSSam Clegg // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c94d393aSSam Clegg // 7c94d393aSSam Clegg //===----------------------------------------------------------------------===// 8c94d393aSSam Clegg 9c94d393aSSam Clegg #include "SymbolTable.h" 10c94d393aSSam Clegg #include "Config.h" 115fa274beSSam Clegg #include "InputChunks.h" 12e915a71fSHeejin Ahn #include "InputEvent.h" 1393102974SSam Clegg #include "InputGlobal.h" 14b8621596SSam Clegg #include "WriterUtils.h" 15c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h" 162017d52bSRui Ueyama #include "lld/Common/Memory.h" 177d67dd11SRui Ueyama #include "llvm/ADT/SetVector.h" 18c94d393aSSam Clegg 19c94d393aSSam Clegg #define DEBUG_TYPE "lld" 20c94d393aSSam Clegg 21c94d393aSSam Clegg using namespace llvm; 2220db381bSSam Clegg using namespace llvm::wasm; 2345218f4aSSam Clegg using namespace llvm::object; 24c94d393aSSam Clegg 2533c59abfSFangrui Song namespace lld { 2633c59abfSFangrui Song namespace wasm { 2733c59abfSFangrui Song SymbolTable *symtab; 28c94d393aSSam Clegg 29136d27abSRui Ueyama void SymbolTable::addFile(InputFile *file) { 30136d27abSRui Ueyama log("Processing: " + toString(file)); 31a282a61bSSam Clegg 32a282a61bSSam Clegg // .a file 33136d27abSRui Ueyama if (auto *f = dyn_cast<ArchiveFile>(file)) { 34136d27abSRui Ueyama f->parse(); 35a282a61bSSam Clegg return; 36a282a61bSSam Clegg } 37a282a61bSSam Clegg 38a282a61bSSam Clegg // .so file 39136d27abSRui Ueyama if (auto *f = dyn_cast<SharedFile>(file)) { 40136d27abSRui Ueyama sharedFiles.push_back(f); 41a282a61bSSam Clegg return; 42a282a61bSSam Clegg } 43a282a61bSSam Clegg 44136d27abSRui Ueyama if (config->trace) 45136d27abSRui Ueyama message(toString(file)); 46c94d393aSSam Clegg 47c729c1b4SSam Clegg // LLVM bitcode file 48136d27abSRui Ueyama if (auto *f = dyn_cast<BitcodeFile>(file)) { 49136d27abSRui Ueyama f->parse(); 50136d27abSRui Ueyama bitcodeFiles.push_back(f); 51a282a61bSSam Clegg return; 52a282a61bSSam Clegg } 53a282a61bSSam Clegg 54a282a61bSSam Clegg // Regular object file 55136d27abSRui Ueyama auto *f = cast<ObjFile>(file); 56136d27abSRui Ueyama f->parse(false); 57136d27abSRui Ueyama objectFiles.push_back(f); 58c94d393aSSam Clegg } 59c94d393aSSam Clegg 60c729c1b4SSam Clegg // This function is where all the optimizations of link-time 61c729c1b4SSam Clegg // optimization happens. When LTO is in use, some input files are 62c729c1b4SSam Clegg // not in native object file format but in the LLVM bitcode format. 63c729c1b4SSam Clegg // This function compiles bitcode files into a few big native files 64c729c1b4SSam Clegg // using LLVM functions and replaces bitcode symbols with the results. 65c729c1b4SSam Clegg // Because all bitcode files that the program consists of are passed 66c729c1b4SSam Clegg // to the compiler at once, it can do whole-program optimization. 67c729c1b4SSam Clegg void SymbolTable::addCombinedLTOObject() { 68136d27abSRui Ueyama if (bitcodeFiles.empty()) 69c729c1b4SSam Clegg return; 70c729c1b4SSam Clegg 71c729c1b4SSam Clegg // Compile bitcode files and replace bitcode symbols. 72136d27abSRui Ueyama lto.reset(new BitcodeCompiler); 73136d27abSRui Ueyama for (BitcodeFile *f : bitcodeFiles) 74136d27abSRui Ueyama lto->add(*f); 75c729c1b4SSam Clegg 76136d27abSRui Ueyama for (StringRef filename : lto->compile()) { 77136d27abSRui Ueyama auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), ""); 78136d27abSRui Ueyama obj->parse(true); 79136d27abSRui Ueyama objectFiles.push_back(obj); 80c729c1b4SSam Clegg } 81c729c1b4SSam Clegg } 82c729c1b4SSam Clegg 83136d27abSRui Ueyama Symbol *SymbolTable::find(StringRef name) { 84136d27abSRui Ueyama auto it = symMap.find(CachedHashStringRef(name)); 85136d27abSRui Ueyama if (it == symMap.end() || it->second == -1) 861f3f774fSSam Clegg return nullptr; 87136d27abSRui Ueyama return symVector[it->second]; 881f3f774fSSam Clegg } 891f3f774fSSam Clegg 90136d27abSRui Ueyama void SymbolTable::replace(StringRef name, Symbol* sym) { 91136d27abSRui Ueyama auto it = symMap.find(CachedHashStringRef(name)); 92136d27abSRui Ueyama symVector[it->second] = sym; 936540e570SSam Clegg } 946540e570SSam Clegg 95136d27abSRui Ueyama std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) { 96136d27abSRui Ueyama bool trace = false; 97136d27abSRui Ueyama auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 98136d27abSRui Ueyama int &symIndex = p.first->second; 99136d27abSRui Ueyama bool isNew = p.second; 100136d27abSRui Ueyama if (symIndex == -1) { 101136d27abSRui Ueyama symIndex = symVector.size(); 102136d27abSRui Ueyama trace = true; 103136d27abSRui Ueyama isNew = true; 1041f3f774fSSam Clegg } 1051f3f774fSSam Clegg 106136d27abSRui Ueyama if (!isNew) 107136d27abSRui Ueyama return {symVector[symIndex], false}; 1081f3f774fSSam Clegg 109136d27abSRui Ueyama Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 110136d27abSRui Ueyama sym->isUsedInRegularObj = false; 111136d27abSRui Ueyama sym->canInline = true; 112136d27abSRui Ueyama sym->traced = trace; 113136d27abSRui Ueyama symVector.emplace_back(sym); 114136d27abSRui Ueyama return {sym, true}; 115c94d393aSSam Clegg } 116c94d393aSSam Clegg 117136d27abSRui Ueyama std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, 118136d27abSRui Ueyama const InputFile *file) { 119136d27abSRui Ueyama Symbol *s; 120136d27abSRui Ueyama bool wasInserted; 121136d27abSRui Ueyama std::tie(s, wasInserted) = insertName(name); 1221f3f774fSSam Clegg 123136d27abSRui Ueyama if (!file || file->kind() == InputFile::ObjectKind) 124136d27abSRui Ueyama s->isUsedInRegularObj = true; 1251f3f774fSSam Clegg 126136d27abSRui Ueyama return {s, wasInserted}; 127c94d393aSSam Clegg } 128c94d393aSSam Clegg 129136d27abSRui Ueyama static void reportTypeError(const Symbol *existing, const InputFile *file, 130136d27abSRui Ueyama llvm::wasm::WasmSymbolType type) { 131136d27abSRui Ueyama error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " + 132136d27abSRui Ueyama toString(existing->getWasmType()) + " in " + 133136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined as " + toString(type) + 134136d27abSRui Ueyama " in " + toString(file)); 135e3498ec5SRui Ueyama } 136e3498ec5SRui Ueyama 1376f4286fbSHeejin Ahn // Check the type of new symbol matches that of the symbol is replacing. 1386540e570SSam Clegg // Returns true if the function types match, false is there is a singature 1396540e570SSam Clegg // mismatch. 140136d27abSRui Ueyama static bool signatureMatches(FunctionSymbol *existing, 141136d27abSRui Ueyama const WasmSignature *newSig) { 142136d27abSRui Ueyama const WasmSignature *oldSig = existing->signature; 143d506b0a4SSam Clegg 144d506b0a4SSam Clegg // If either function is missing a signature (this happend for bitcode 145d506b0a4SSam Clegg // symbols) then assume they match. Any mismatch will be reported later 146d506b0a4SSam Clegg // when the LTO objects are added. 147136d27abSRui Ueyama if (!newSig || !oldSig) 1486540e570SSam Clegg return true; 149cefbf9acSSam Clegg 150136d27abSRui Ueyama return *newSig == *oldSig; 151e3498ec5SRui Ueyama } 152e3498ec5SRui Ueyama 153136d27abSRui Ueyama static void checkGlobalType(const Symbol *existing, const InputFile *file, 154136d27abSRui Ueyama const WasmGlobalType *newType) { 155136d27abSRui Ueyama if (!isa<GlobalSymbol>(existing)) { 156136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL); 157b8621596SSam Clegg return; 158b8621596SSam Clegg } 159b8621596SSam Clegg 160136d27abSRui Ueyama const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType(); 161136d27abSRui Ueyama if (*newType != *oldType) { 162136d27abSRui Ueyama error("Global type mismatch: " + existing->getName() + "\n>>> defined as " + 163136d27abSRui Ueyama toString(*oldType) + " in " + toString(existing->getFile()) + 164136d27abSRui Ueyama "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 165c94d393aSSam Clegg } 16624b3dcd4SSam Clegg } 16724b3dcd4SSam Clegg 168136d27abSRui Ueyama static void checkEventType(const Symbol *existing, const InputFile *file, 169136d27abSRui Ueyama const WasmEventType *newType, 170136d27abSRui Ueyama const WasmSignature *newSig) { 171136d27abSRui Ueyama auto existingEvent = dyn_cast<EventSymbol>(existing); 172136d27abSRui Ueyama if (!isa<EventSymbol>(existing)) { 173136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT); 174e915a71fSHeejin Ahn return; 175e915a71fSHeejin Ahn } 176e915a71fSHeejin Ahn 177136d27abSRui Ueyama const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType(); 178136d27abSRui Ueyama const WasmSignature *oldSig = existingEvent->signature; 179136d27abSRui Ueyama if (newType->Attribute != oldType->Attribute) 180136d27abSRui Ueyama error("Event type mismatch: " + existing->getName() + "\n>>> defined as " + 181136d27abSRui Ueyama toString(*oldType) + " in " + toString(existing->getFile()) + 182136d27abSRui Ueyama "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 183136d27abSRui Ueyama if (*newSig != *oldSig) 184136d27abSRui Ueyama warn("Event signature mismatch: " + existing->getName() + 185136d27abSRui Ueyama "\n>>> defined as " + toString(*oldSig) + " in " + 186136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined as " + 187136d27abSRui Ueyama toString(*newSig) + " in " + toString(file)); 188e915a71fSHeejin Ahn } 189e915a71fSHeejin Ahn 190136d27abSRui Ueyama static void checkDataType(const Symbol *existing, const InputFile *file) { 191136d27abSRui Ueyama if (!isa<DataSymbol>(existing)) 192136d27abSRui Ueyama reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA); 193e3498ec5SRui Ueyama } 194e3498ec5SRui Ueyama 195136d27abSRui Ueyama DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, 196136d27abSRui Ueyama uint32_t flags, 197136d27abSRui Ueyama InputFunction *function) { 198136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); 199136d27abSRui Ueyama assert(!find(name)); 200136d27abSRui Ueyama syntheticFunctions.emplace_back(function); 201136d27abSRui Ueyama return replaceSymbol<DefinedFunction>(insertName(name).first, name, 202136d27abSRui Ueyama flags, nullptr, function); 20350686856SSam Clegg } 20450686856SSam Clegg 2058e8ddaa3SSam Clegg // Adds an optional, linker generated, data symbols. The symbol will only be 2068e8ddaa3SSam Clegg // added if there is an undefine reference to it, or if it is explictly exported 2078e8ddaa3SSam Clegg // via the --export flag. Otherwise we don't add the symbol and return nullptr. 208caa0db13SSam Clegg DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, 209caa0db13SSam Clegg uint32_t value) { 210136d27abSRui Ueyama Symbol *s = find(name); 211136d27abSRui Ueyama if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0)) 212136d27abSRui Ueyama s = insertName(name).first; 213136d27abSRui Ueyama else if (!s || s->isDefined()) 2144bce63a0SSam Clegg return nullptr; 215136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n"); 216caa0db13SSam Clegg auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN); 217136d27abSRui Ueyama rtn->setVirtualAddress(value); 218136d27abSRui Ueyama rtn->referenced = true; 2194bce63a0SSam Clegg return rtn; 2204bce63a0SSam Clegg } 2214bce63a0SSam Clegg 222136d27abSRui Ueyama DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, 223136d27abSRui Ueyama uint32_t flags) { 224136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); 225136d27abSRui Ueyama assert(!find(name)); 226136d27abSRui Ueyama return replaceSymbol<DefinedData>(insertName(name).first, name, flags); 227c94d393aSSam Clegg } 228c94d393aSSam Clegg 229136d27abSRui Ueyama DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, 230136d27abSRui Ueyama InputGlobal *global) { 231136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global 232e7245b42SNicola Zaghen << "\n"); 233136d27abSRui Ueyama assert(!find(name)); 234136d27abSRui Ueyama syntheticGlobals.emplace_back(global); 235136d27abSRui Ueyama return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags, 236136d27abSRui Ueyama nullptr, global); 23793102974SSam Clegg } 23893102974SSam Clegg 239136d27abSRui Ueyama static bool shouldReplace(const Symbol *existing, InputFile *newFile, 240136d27abSRui Ueyama uint32_t newFlags) { 241c03c9040SRui Ueyama // If existing symbol is undefined, replace it. 242136d27abSRui Ueyama if (!existing->isDefined()) { 243e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 244136d27abSRui Ueyama << existing->getName() << "\n"); 245c03c9040SRui Ueyama return true; 246c03c9040SRui Ueyama } 247c03c9040SRui Ueyama 248c03c9040SRui Ueyama // Now we have two defined symbols. If the new one is weak, we can ignore it. 249136d27abSRui Ueyama if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 250e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 251c03c9040SRui Ueyama return false; 252c03c9040SRui Ueyama } 253c03c9040SRui Ueyama 254c03c9040SRui Ueyama // If the existing symbol is weak, we should replace it. 255136d27abSRui Ueyama if (existing->isWeak()) { 256e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 257c03c9040SRui Ueyama return true; 258c03c9040SRui Ueyama } 259c03c9040SRui Ueyama 260c03c9040SRui Ueyama // Neither symbol is week. They conflict. 261136d27abSRui Ueyama error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + 262136d27abSRui Ueyama toString(existing->getFile()) + "\n>>> defined in " + 263136d27abSRui Ueyama toString(newFile)); 264c03c9040SRui Ueyama return true; 265b8621596SSam Clegg } 26693e559b1SSam Clegg 267136d27abSRui Ueyama Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags, 268136d27abSRui Ueyama InputFile *file, 269136d27abSRui Ueyama InputFunction *function) { 270136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " [" 271136d27abSRui Ueyama << (function ? toString(function->signature) : "none") 2728b0b48f3SSam Clegg << "]\n"); 273136d27abSRui Ueyama Symbol *s; 274136d27abSRui Ueyama bool wasInserted; 275136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 276c729c1b4SSam Clegg 277136d27abSRui Ueyama auto replaceSym = [&](Symbol *sym) { 2786540e570SSam Clegg // If the new defined function doesn't have signture (i.e. bitcode 2796540e570SSam Clegg // functions) but the old symbol does, then preserve the old signature 280136d27abSRui Ueyama const WasmSignature *oldSig = s->getSignature(); 281136d27abSRui Ueyama auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function); 282136d27abSRui Ueyama if (!newSym->signature) 283136d27abSRui Ueyama newSym->signature = oldSig; 2846540e570SSam Clegg }; 2856540e570SSam Clegg 286136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 287136d27abSRui Ueyama replaceSym(s); 288136d27abSRui Ueyama return s; 289e3498ec5SRui Ueyama } 290e3498ec5SRui Ueyama 291136d27abSRui Ueyama auto existingFunction = dyn_cast<FunctionSymbol>(s); 292136d27abSRui Ueyama if (!existingFunction) { 293136d27abSRui Ueyama reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 294136d27abSRui Ueyama return s; 2958b0b48f3SSam Clegg } 2966540e570SSam Clegg 297136d27abSRui Ueyama bool checkSig = true; 298136d27abSRui Ueyama if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) 299136d27abSRui Ueyama checkSig = ud->isCalledDirectly; 30059f959ffSSam Clegg 301136d27abSRui Ueyama if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) { 302136d27abSRui Ueyama Symbol* variant; 303136d27abSRui Ueyama if (getFunctionVariant(s, &function->signature, file, &variant)) 3046540e570SSam Clegg // New variant, always replace 305136d27abSRui Ueyama replaceSym(variant); 306136d27abSRui Ueyama else if (shouldReplace(s, file, flags)) 3076540e570SSam Clegg // Variant already exists, replace it after checking shouldReplace 308136d27abSRui Ueyama replaceSym(variant); 3096540e570SSam Clegg 3106540e570SSam Clegg // This variant we found take the place in the symbol table as the primary 3116540e570SSam Clegg // variant. 312136d27abSRui Ueyama replace(name, variant); 313136d27abSRui Ueyama return variant; 3146540e570SSam Clegg } 3156540e570SSam Clegg 3166540e570SSam Clegg // Existing function with matching signature. 317136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 318136d27abSRui Ueyama replaceSym(s); 3196540e570SSam Clegg 320136d27abSRui Ueyama return s; 32193e559b1SSam Clegg } 32293e559b1SSam Clegg 323136d27abSRui Ueyama Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, 324136d27abSRui Ueyama InputFile *file, InputSegment *segment, 325136d27abSRui Ueyama uint32_t address, uint32_t size) { 326136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address 327e7245b42SNicola Zaghen << "\n"); 328136d27abSRui Ueyama Symbol *s; 329136d27abSRui Ueyama bool wasInserted; 330136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 331c729c1b4SSam Clegg 332136d27abSRui Ueyama auto replaceSym = [&]() { 333136d27abSRui Ueyama replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size); 3346540e570SSam Clegg }; 3356540e570SSam Clegg 336136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 337136d27abSRui Ueyama replaceSym(); 338136d27abSRui Ueyama return s; 339e3498ec5SRui Ueyama } 340e3498ec5SRui Ueyama 341136d27abSRui Ueyama checkDataType(s, file); 342e3498ec5SRui Ueyama 343136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 344136d27abSRui Ueyama replaceSym(); 345136d27abSRui Ueyama return s; 346c94d393aSSam Clegg } 347c94d393aSSam Clegg 348136d27abSRui Ueyama Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags, 349136d27abSRui Ueyama InputFile *file, InputGlobal *global) { 350136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n"); 3514c2cbfe6SSam Clegg 352136d27abSRui Ueyama Symbol *s; 353136d27abSRui Ueyama bool wasInserted; 354136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 355c729c1b4SSam Clegg 356136d27abSRui Ueyama auto replaceSym = [&]() { 357136d27abSRui Ueyama replaceSymbol<DefinedGlobal>(s, name, flags, file, global); 3586540e570SSam Clegg }; 3596540e570SSam Clegg 360136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 361136d27abSRui Ueyama replaceSym(); 362136d27abSRui Ueyama return s; 36393102974SSam Clegg } 36493102974SSam Clegg 365136d27abSRui Ueyama checkGlobalType(s, file, &global->getType()); 366e3498ec5SRui Ueyama 367136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 368136d27abSRui Ueyama replaceSym(); 369136d27abSRui Ueyama return s; 370e3498ec5SRui Ueyama } 371e3498ec5SRui Ueyama 372136d27abSRui Ueyama Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags, 373136d27abSRui Ueyama InputFile *file, InputEvent *event) { 374136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n"); 375e915a71fSHeejin Ahn 376136d27abSRui Ueyama Symbol *s; 377136d27abSRui Ueyama bool wasInserted; 378136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 379e915a71fSHeejin Ahn 380136d27abSRui Ueyama auto replaceSym = [&]() { 381136d27abSRui Ueyama replaceSymbol<DefinedEvent>(s, name, flags, file, event); 3826540e570SSam Clegg }; 3836540e570SSam Clegg 384136d27abSRui Ueyama if (wasInserted || s->isLazy()) { 385136d27abSRui Ueyama replaceSym(); 386136d27abSRui Ueyama return s; 387e915a71fSHeejin Ahn } 388e915a71fSHeejin Ahn 389136d27abSRui Ueyama checkEventType(s, file, &event->getType(), &event->signature); 390e915a71fSHeejin Ahn 391136d27abSRui Ueyama if (shouldReplace(s, file, flags)) 392136d27abSRui Ueyama replaceSym(); 393136d27abSRui Ueyama return s; 394e915a71fSHeejin Ahn } 395e915a71fSHeejin Ahn 396*67b05584SSam Clegg // This function get called when an undefined symbol is added, and there is 397*67b05584SSam Clegg // already an existing one in the symbols table. In this case we check that 398*67b05584SSam Clegg // custom 'import-module' and 'import-field' symbol attributes agree. 399*67b05584SSam Clegg // With LTO these attributes are not avialable when the bitcode is read and only 400*67b05584SSam Clegg // become available when the LTO object is read. In this case we silently 401*67b05584SSam Clegg // replace the empty attributes with the valid ones. 402*67b05584SSam Clegg template <typename T> 403*67b05584SSam Clegg static void setImportAttributes(T *existing, StringRef importName, 404*67b05584SSam Clegg StringRef importModule, InputFile *file) { 405*67b05584SSam Clegg if (!importName.empty()) { 406*67b05584SSam Clegg if (existing->importName.empty()) 407*67b05584SSam Clegg existing->importName = importName; 408*67b05584SSam Clegg if (existing->importName != importName) 409*67b05584SSam Clegg error("import name mismatch for symbol: " + toString(*existing) + 410*67b05584SSam Clegg "\n>>> defined as " + existing->importName + " in " + 411*67b05584SSam Clegg toString(existing->getFile()) + "\n>>> defined as " + importName + 412*67b05584SSam Clegg " in " + toString(file)); 413*67b05584SSam Clegg } 414*67b05584SSam Clegg 415*67b05584SSam Clegg if (!importModule.empty()) { 416*67b05584SSam Clegg if (existing->importModule.empty()) 417*67b05584SSam Clegg existing->importModule = importModule; 418*67b05584SSam Clegg if (existing->importModule != importModule) 419*67b05584SSam Clegg error("import module mismatch for symbol: " + toString(*existing) + 420*67b05584SSam Clegg "\n>>> defined as " + existing->importModule + " in " + 421*67b05584SSam Clegg toString(existing->getFile()) + "\n>>> defined as " + importModule + 422*67b05584SSam Clegg " in " + toString(file)); 423*67b05584SSam Clegg } 424*67b05584SSam Clegg } 425*67b05584SSam Clegg 426136d27abSRui Ueyama Symbol *SymbolTable::addUndefinedFunction(StringRef name, StringRef importName, 427136d27abSRui Ueyama StringRef importModule, 428136d27abSRui Ueyama uint32_t flags, InputFile *file, 429136d27abSRui Ueyama const WasmSignature *sig, 430136d27abSRui Ueyama bool isCalledDirectly) { 431136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" 432136d27abSRui Ueyama << (sig ? toString(*sig) : "none") 433136d27abSRui Ueyama << "] IsCalledDirectly:" << isCalledDirectly << "\n"); 434f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 435c03c9040SRui Ueyama 436136d27abSRui Ueyama Symbol *s; 437136d27abSRui Ueyama bool wasInserted; 438136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 439136d27abSRui Ueyama if (s->traced) 440136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 441c729c1b4SSam Clegg 442136d27abSRui Ueyama auto replaceSym = [&]() { 443136d27abSRui Ueyama replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags, 444136d27abSRui Ueyama file, sig, isCalledDirectly); 4456540e570SSam Clegg }; 4466540e570SSam Clegg 447136d27abSRui Ueyama if (wasInserted) 448136d27abSRui Ueyama replaceSym(); 449136d27abSRui Ueyama else if (auto *lazy = dyn_cast<LazySymbol>(s)) 450136d27abSRui Ueyama lazy->fetch(); 4516540e570SSam Clegg else { 452136d27abSRui Ueyama auto existingFunction = dyn_cast<FunctionSymbol>(s); 453136d27abSRui Ueyama if (!existingFunction) { 454136d27abSRui Ueyama reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 455136d27abSRui Ueyama return s; 4566540e570SSam Clegg } 457*67b05584SSam Clegg auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction); 458136d27abSRui Ueyama if (!existingFunction->signature && sig) 459136d27abSRui Ueyama existingFunction->signature = sig; 460fecfc592SSam Clegg if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { 461fecfc592SSam Clegg // If the existing undefined functions is not called direcltly then let 462fecfc592SSam Clegg // this one take precedence. Otherwise the existing function is either 463fecfc592SSam Clegg // direclty called or defined, in which case we need a function variant. 464fecfc592SSam Clegg if (existingUndefined && !existingUndefined->isCalledDirectly) 465136d27abSRui Ueyama replaceSym(); 466fecfc592SSam Clegg else if (getFunctionVariant(s, sig, file, &s)) 467fecfc592SSam Clegg replaceSym(); 468fecfc592SSam Clegg } 469*67b05584SSam Clegg if (existingUndefined) 470*67b05584SSam Clegg setImportAttributes(existingUndefined, importName, importModule, file); 4716540e570SSam Clegg } 472cefbf9acSSam Clegg 473136d27abSRui Ueyama return s; 474c03c9040SRui Ueyama } 475c03c9040SRui Ueyama 476136d27abSRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, 477136d27abSRui Ueyama InputFile *file) { 478136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); 479f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 48093102974SSam Clegg 481136d27abSRui Ueyama Symbol *s; 482136d27abSRui Ueyama bool wasInserted; 483136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 484136d27abSRui Ueyama if (s->traced) 485136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 486f989a92dSSam Clegg 487136d27abSRui Ueyama if (wasInserted) 488136d27abSRui Ueyama replaceSymbol<UndefinedData>(s, name, flags, file); 489136d27abSRui Ueyama else if (auto *lazy = dyn_cast<LazySymbol>(s)) 490136d27abSRui Ueyama lazy->fetch(); 491136d27abSRui Ueyama else if (s->isDefined()) 492136d27abSRui Ueyama checkDataType(s, file); 493136d27abSRui Ueyama return s; 494c94d393aSSam Clegg } 495c94d393aSSam Clegg 496136d27abSRui Ueyama Symbol *SymbolTable::addUndefinedGlobal(StringRef name, StringRef importName, 497136d27abSRui Ueyama StringRef importModule, uint32_t flags, 498136d27abSRui Ueyama InputFile *file, 499136d27abSRui Ueyama const WasmGlobalType *type) { 500136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); 501f6f4b98fSSam Clegg assert(flags & WASM_SYMBOL_UNDEFINED); 502e3498ec5SRui Ueyama 503136d27abSRui Ueyama Symbol *s; 504136d27abSRui Ueyama bool wasInserted; 505136d27abSRui Ueyama std::tie(s, wasInserted) = insert(name, file); 506136d27abSRui Ueyama if (s->traced) 507136d27abSRui Ueyama printTraceSymbolUndefined(name, file); 508c729c1b4SSam Clegg 509136d27abSRui Ueyama if (wasInserted) 510136d27abSRui Ueyama replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, 511136d27abSRui Ueyama file, type); 512136d27abSRui Ueyama else if (auto *lazy = dyn_cast<LazySymbol>(s)) 513136d27abSRui Ueyama lazy->fetch(); 514136d27abSRui Ueyama else if (s->isDefined()) 515136d27abSRui Ueyama checkGlobalType(s, file, type); 516136d27abSRui Ueyama return s; 517e3498ec5SRui Ueyama } 518e3498ec5SRui Ueyama 519136d27abSRui Ueyama void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) { 520136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n"); 521136d27abSRui Ueyama StringRef name = sym->getName(); 522c03c9040SRui Ueyama 523136d27abSRui Ueyama Symbol *s; 524136d27abSRui Ueyama bool wasInserted; 525136d27abSRui Ueyama std::tie(s, wasInserted) = insertName(name); 526c03c9040SRui Ueyama 527136d27abSRui Ueyama if (wasInserted) { 528136d27abSRui Ueyama replaceSymbol<LazySymbol>(s, name, 0, file, *sym); 529c03c9040SRui Ueyama return; 530c03c9040SRui Ueyama } 531c03c9040SRui Ueyama 532136d27abSRui Ueyama if (!s->isUndefined()) 53337b4ee52SSam Clegg return; 53437b4ee52SSam Clegg 53537b4ee52SSam Clegg // The existing symbol is undefined, load a new one from the archive, 53637b4ee52SSam Clegg // unless the the existing symbol is weak in which case replace the undefined 53737b4ee52SSam Clegg // symbols with a LazySymbol. 538136d27abSRui Ueyama if (s->isWeak()) { 539136d27abSRui Ueyama const WasmSignature *oldSig = nullptr; 54037b4ee52SSam Clegg // In the case of an UndefinedFunction we need to preserve the expected 54137b4ee52SSam Clegg // signature. 542136d27abSRui Ueyama if (auto *f = dyn_cast<UndefinedFunction>(s)) 543136d27abSRui Ueyama oldSig = f->signature; 54437b4ee52SSam Clegg LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 545136d27abSRui Ueyama auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, 546136d27abSRui Ueyama file, *sym); 547136d27abSRui Ueyama newSym->signature = oldSig; 54837b4ee52SSam Clegg return; 54937b4ee52SSam Clegg } 55037b4ee52SSam Clegg 551e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 552136d27abSRui Ueyama file->addMember(sym); 553c94d393aSSam Clegg } 554e0f6fcd0SSam Clegg 555136d27abSRui Ueyama bool SymbolTable::addComdat(StringRef name) { 556136d27abSRui Ueyama return comdatGroups.insert(CachedHashStringRef(name)).second; 557e0f6fcd0SSam Clegg } 5581f3f774fSSam Clegg 5596540e570SSam Clegg // The new signature doesn't match. Create a variant to the symbol with the 5606540e570SSam Clegg // signature encoded in the name and return that instead. These symbols are 5616540e570SSam Clegg // then unified later in handleSymbolVariants. 562136d27abSRui Ueyama bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, 563136d27abSRui Ueyama const InputFile *file, Symbol **out) { 564136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " 565136d27abSRui Ueyama << " " << toString(*sig) << "\n"); 566136d27abSRui Ueyama Symbol *variant = nullptr; 5676540e570SSam Clegg 5686540e570SSam Clegg // Linear search through symbol variants. Should never be more than two 5696540e570SSam Clegg // or three entries here. 570136d27abSRui Ueyama auto &variants = symVariants[CachedHashStringRef(sym->getName())]; 571136d27abSRui Ueyama if (variants.empty()) 572136d27abSRui Ueyama variants.push_back(sym); 5736540e570SSam Clegg 574136d27abSRui Ueyama for (Symbol* v : variants) { 575136d27abSRui Ueyama if (*v->getSignature() == *sig) { 576136d27abSRui Ueyama variant = v; 5776540e570SSam Clegg break; 5786540e570SSam Clegg } 5796540e570SSam Clegg } 5806540e570SSam Clegg 581136d27abSRui Ueyama bool wasAdded = !variant; 582136d27abSRui Ueyama if (wasAdded) { 5836540e570SSam Clegg // Create a new variant; 5846540e570SSam Clegg LLVM_DEBUG(dbgs() << "added new variant\n"); 585136d27abSRui Ueyama variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 586136d27abSRui Ueyama variants.push_back(variant); 5876540e570SSam Clegg } else { 588136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); 589136d27abSRui Ueyama assert(*variant->getSignature() == *sig); 5906540e570SSam Clegg } 5916540e570SSam Clegg 592136d27abSRui Ueyama *out = variant; 593136d27abSRui Ueyama return wasAdded; 5946540e570SSam Clegg } 5956540e570SSam Clegg 5961f3f774fSSam Clegg // Set a flag for --trace-symbol so that we can print out a log message 5971f3f774fSSam Clegg // if a new symbol with the same name is inserted into the symbol table. 598136d27abSRui Ueyama void SymbolTable::trace(StringRef name) { 599136d27abSRui Ueyama symMap.insert({CachedHashStringRef(name), -1}); 6001f3f774fSSam Clegg } 601230dc11dSSam Clegg 602136d27abSRui Ueyama void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { 603a5ca34e6SSam Clegg // Swap symbols as instructed by -wrap. 604136d27abSRui Ueyama int &origIdx = symMap[CachedHashStringRef(sym->getName())]; 605136d27abSRui Ueyama int &realIdx= symMap[CachedHashStringRef(real->getName())]; 606136d27abSRui Ueyama int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; 607136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); 608a5ca34e6SSam Clegg 609a5ca34e6SSam Clegg // Anyone looking up __real symbols should get the original 610136d27abSRui Ueyama realIdx = origIdx; 611a5ca34e6SSam Clegg // Anyone looking up the original should get the __wrap symbol 612136d27abSRui Ueyama origIdx = wrapIdx; 613a5ca34e6SSam Clegg } 614a5ca34e6SSam Clegg 615136d27abSRui Ueyama static const uint8_t unreachableFn[] = { 616230dc11dSSam Clegg 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 617230dc11dSSam Clegg 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 618230dc11dSSam Clegg }; 619230dc11dSSam Clegg 620230dc11dSSam Clegg // Replace the given symbol body with an unreachable function. 621230dc11dSSam Clegg // This is used by handleWeakUndefines in order to generate a callable 6226540e570SSam Clegg // equivalent of an undefined function and also handleSymbolVariants for 6236540e570SSam Clegg // undefined functions that don't match the signature of the definition. 624136d27abSRui Ueyama InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, 625136d27abSRui Ueyama const WasmSignature &sig, 626136d27abSRui Ueyama StringRef debugName) { 627136d27abSRui Ueyama auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); 628136d27abSRui Ueyama func->setBody(unreachableFn); 629136d27abSRui Ueyama syntheticFunctions.emplace_back(func); 630136d27abSRui Ueyama replaceSymbol<DefinedFunction>(sym, sym->getName(), sym->getFlags(), nullptr, 631136d27abSRui Ueyama func); 632136d27abSRui Ueyama return func; 633230dc11dSSam Clegg } 634230dc11dSSam Clegg 635230dc11dSSam Clegg // For weak undefined functions, there may be "call" instructions that reference 636230dc11dSSam Clegg // the symbol. In this case, we need to synthesise a dummy/stub function that 637230dc11dSSam Clegg // will abort at runtime, so that relocations can still provided an operand to 638230dc11dSSam Clegg // the call instruction that passes Wasm validation. 639230dc11dSSam Clegg void SymbolTable::handleWeakUndefines() { 640136d27abSRui Ueyama for (Symbol *sym : getSymbols()) { 641136d27abSRui Ueyama if (!sym->isUndefWeak()) 642230dc11dSSam Clegg continue; 643230dc11dSSam Clegg 644136d27abSRui Ueyama const WasmSignature *sig = sym->getSignature(); 645136d27abSRui Ueyama if (!sig) { 646230dc11dSSam Clegg // It is possible for undefined functions not to have a signature (eg. if 647230dc11dSSam Clegg // added via "--undefined"), but weak undefined ones do have a signature. 6486540e570SSam Clegg // Lazy symbols may not be functions and therefore Sig can still be null 6496540e570SSam Clegg // in some circumstantce. 650136d27abSRui Ueyama assert(!isa<FunctionSymbol>(sym)); 651230dc11dSSam Clegg continue; 6526540e570SSam Clegg } 653230dc11dSSam Clegg 654230dc11dSSam Clegg // Add a synthetic dummy for weak undefined functions. These dummies will 655230dc11dSSam Clegg // be GC'd if not used as the target of any "call" instructions. 656136d27abSRui Ueyama StringRef debugName = saver.save("undefined:" + toString(*sym)); 657136d27abSRui Ueyama InputFunction* func = replaceWithUnreachable(sym, *sig, debugName); 658230dc11dSSam Clegg // Ensure it compares equal to the null pointer, and so that table relocs 659230dc11dSSam Clegg // don't pull in the stub body (only call-operand relocs should do that). 660136d27abSRui Ueyama func->setTableIndex(0); 661230dc11dSSam Clegg // Hide our dummy to prevent export. 662136d27abSRui Ueyama sym->setHidden(true); 663230dc11dSSam Clegg } 664230dc11dSSam Clegg } 6656540e570SSam Clegg 666136d27abSRui Ueyama static void reportFunctionSignatureMismatch(StringRef symName, 667136d27abSRui Ueyama FunctionSymbol *a, 668136d27abSRui Ueyama FunctionSymbol *b, bool isError) { 669136d27abSRui Ueyama std::string msg = ("function signature mismatch: " + symName + 670136d27abSRui Ueyama "\n>>> defined as " + toString(*a->signature) + " in " + 671136d27abSRui Ueyama toString(a->getFile()) + "\n>>> defined as " + 672136d27abSRui Ueyama toString(*b->signature) + " in " + toString(b->getFile())) 6736540e570SSam Clegg .str(); 674136d27abSRui Ueyama if (isError) 6756540e570SSam Clegg error(msg); 6766540e570SSam Clegg else 6776540e570SSam Clegg warn(msg); 6786540e570SSam Clegg } 6796540e570SSam Clegg 6806540e570SSam Clegg // Remove any variant symbols that were created due to function signature 6816540e570SSam Clegg // mismatches. 6826540e570SSam Clegg void SymbolTable::handleSymbolVariants() { 683136d27abSRui Ueyama for (auto pair : symVariants) { 6846540e570SSam Clegg // Push the initial symbol onto the list of variants. 685136d27abSRui Ueyama StringRef symName = pair.first.val(); 686136d27abSRui Ueyama std::vector<Symbol *> &variants = pair.second; 6876540e570SSam Clegg 6886540e570SSam Clegg #ifndef NDEBUG 689136d27abSRui Ueyama LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() 690136d27abSRui Ueyama << ") variants: " << symName << "\n"); 691136d27abSRui Ueyama for (auto *s: variants) { 692136d27abSRui Ueyama auto *f = cast<FunctionSymbol>(s); 693136d27abSRui Ueyama LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " 694136d27abSRui Ueyama << toString(*f->signature) << "\n"); 6956540e570SSam Clegg } 6966540e570SSam Clegg #endif 6976540e570SSam Clegg 6986540e570SSam Clegg // Find the one definition. 699136d27abSRui Ueyama DefinedFunction *defined = nullptr; 700136d27abSRui Ueyama for (auto *symbol : variants) { 701136d27abSRui Ueyama if (auto f = dyn_cast<DefinedFunction>(symbol)) { 702136d27abSRui Ueyama defined = f; 7036540e570SSam Clegg break; 7046540e570SSam Clegg } 7056540e570SSam Clegg } 7066540e570SSam Clegg 7076540e570SSam Clegg // If there are no definitions, and the undefined symbols disagree on 7086540e570SSam Clegg // the signature, there is not we can do since we don't know which one 7096540e570SSam Clegg // to use as the signature on the import. 710136d27abSRui Ueyama if (!defined) { 711136d27abSRui Ueyama reportFunctionSignatureMismatch(symName, 712136d27abSRui Ueyama cast<FunctionSymbol>(variants[0]), 713136d27abSRui Ueyama cast<FunctionSymbol>(variants[1]), true); 7146540e570SSam Clegg return; 7156540e570SSam Clegg } 7166540e570SSam Clegg 717136d27abSRui Ueyama for (auto *symbol : variants) { 718136d27abSRui Ueyama if (symbol != defined) { 719136d27abSRui Ueyama auto *f = cast<FunctionSymbol>(symbol); 720136d27abSRui Ueyama reportFunctionSignatureMismatch(symName, f, defined, false); 721136d27abSRui Ueyama StringRef debugName = saver.save("unreachable:" + toString(*f)); 722136d27abSRui Ueyama replaceWithUnreachable(f, *f->signature, debugName); 7236540e570SSam Clegg } 7246540e570SSam Clegg } 7256540e570SSam Clegg } 7266540e570SSam Clegg } 72733c59abfSFangrui Song 72833c59abfSFangrui Song } // namespace wasm 72933c59abfSFangrui Song } // namespace lld 730