1c94d393aSSam Clegg //===- SymbolTable.cpp ----------------------------------------------------===// 2c94d393aSSam Clegg // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c94d393aSSam Clegg // 7c94d393aSSam Clegg //===----------------------------------------------------------------------===// 8c94d393aSSam Clegg 9c94d393aSSam Clegg #include "SymbolTable.h" 10c94d393aSSam Clegg #include "Config.h" 115fa274beSSam Clegg #include "InputChunks.h" 12e915a71fSHeejin Ahn #include "InputEvent.h" 1393102974SSam Clegg #include "InputGlobal.h" 14b8621596SSam Clegg #include "WriterUtils.h" 15c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h" 162017d52bSRui Ueyama #include "lld/Common/Memory.h" 177d67dd11SRui Ueyama #include "llvm/ADT/SetVector.h" 18c94d393aSSam Clegg 19c94d393aSSam Clegg #define DEBUG_TYPE "lld" 20c94d393aSSam Clegg 21c94d393aSSam Clegg using namespace llvm; 2220db381bSSam Clegg using namespace llvm::wasm; 2345218f4aSSam Clegg using namespace llvm::object; 24c94d393aSSam Clegg using namespace lld; 25c94d393aSSam Clegg using namespace lld::wasm; 26c94d393aSSam Clegg 27c94d393aSSam Clegg SymbolTable *lld::wasm::Symtab; 28c94d393aSSam Clegg 296540e570SSam Clegg static char encodeValType(ValType Type) { 306540e570SSam Clegg switch (Type) { 316540e570SSam Clegg case ValType::I32: 326540e570SSam Clegg return 'i'; 336540e570SSam Clegg case ValType::I64: 346540e570SSam Clegg return 'j'; 356540e570SSam Clegg case ValType::F32: 366540e570SSam Clegg return 'f'; 376540e570SSam Clegg case ValType::F64: 386540e570SSam Clegg return 'd'; 396540e570SSam Clegg case ValType::V128: 406540e570SSam Clegg return 'V'; 416540e570SSam Clegg case ValType::EXCEPT_REF: 426540e570SSam Clegg return 'e'; 436540e570SSam Clegg } 446540e570SSam Clegg llvm_unreachable("invalid wasm type"); 456540e570SSam Clegg } 466540e570SSam Clegg 476540e570SSam Clegg static std::string encodeSignature(const WasmSignature &Sig) { 486540e570SSam Clegg std::string S = ":"; 496540e570SSam Clegg for (ValType Type : Sig.Returns) 506540e570SSam Clegg S += encodeValType(Type); 516540e570SSam Clegg S += ':'; 526540e570SSam Clegg for (ValType Type : Sig.Params) 536540e570SSam Clegg S += encodeValType(Type); 546540e570SSam Clegg return S; 556540e570SSam Clegg } 566540e570SSam Clegg 576540e570SSam Clegg static StringRef getVariantName(StringRef BaseName, const WasmSignature &Sig) { 586540e570SSam Clegg return Saver.save(BaseName + encodeSignature(Sig)); 596540e570SSam Clegg } 606540e570SSam Clegg 61c94d393aSSam Clegg void SymbolTable::addFile(InputFile *File) { 62c94d393aSSam Clegg log("Processing: " + toString(File)); 631f3f774fSSam Clegg if (Config->Trace) 641f3f774fSSam Clegg message(toString(File)); 65c94d393aSSam Clegg File->parse(); 66c94d393aSSam Clegg 67c729c1b4SSam Clegg // LLVM bitcode file 68c729c1b4SSam Clegg if (auto *F = dyn_cast<BitcodeFile>(File)) 69c729c1b4SSam Clegg BitcodeFiles.push_back(F); 70c729c1b4SSam Clegg else if (auto *F = dyn_cast<ObjFile>(File)) 71c94d393aSSam Clegg 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. 81c729c1b4SSam Clegg void SymbolTable::addCombinedLTOObject() { 82c729c1b4SSam Clegg if (BitcodeFiles.empty()) 83c729c1b4SSam Clegg return; 84c729c1b4SSam Clegg 85c729c1b4SSam Clegg // Compile bitcode files and replace bitcode symbols. 86c729c1b4SSam Clegg LTO.reset(new BitcodeCompiler); 87c729c1b4SSam Clegg for (BitcodeFile *F : BitcodeFiles) 88c729c1b4SSam Clegg LTO->add(*F); 89c729c1b4SSam Clegg 90c729c1b4SSam Clegg for (StringRef Filename : LTO->compile()) { 91c729c1b4SSam Clegg auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp")); 92c729c1b4SSam Clegg Obj->parse(); 93c729c1b4SSam Clegg ObjectFiles.push_back(Obj); 94c729c1b4SSam Clegg } 95c729c1b4SSam Clegg } 96c729c1b4SSam Clegg 97c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() { 9874fe0ba1SSam Clegg for (Symbol *Sym : SymVector) { 99c729c1b4SSam Clegg if (!Sym->isUndefined() || Sym->isWeak()) 100c729c1b4SSam Clegg continue; 101c729c1b4SSam Clegg if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0) 102c729c1b4SSam Clegg continue; 103c729c1b4SSam Clegg if (!Sym->IsUsedInRegularObj) 104c729c1b4SSam Clegg continue; 10547e2b6b2SSam Clegg error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym)); 106c94d393aSSam Clegg } 107c94d393aSSam Clegg } 108c94d393aSSam Clegg 109c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) { 1101f3f774fSSam Clegg auto It = SymMap.find(CachedHashStringRef(Name)); 1111f3f774fSSam Clegg if (It == SymMap.end() || It->second == -1) 1121f3f774fSSam Clegg return nullptr; 1131f3f774fSSam Clegg return SymVector[It->second]; 1141f3f774fSSam Clegg } 1151f3f774fSSam Clegg 1166540e570SSam Clegg void SymbolTable::replace(StringRef Name, Symbol* Sym) { 1176540e570SSam Clegg auto It = SymMap.find(CachedHashStringRef(Name)); 1186540e570SSam Clegg SymVector[It->second] = Sym; 1196540e570SSam Clegg } 1206540e570SSam Clegg 1211f3f774fSSam Clegg std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) { 1221f3f774fSSam Clegg bool Trace = false; 1231f3f774fSSam Clegg auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); 1241f3f774fSSam Clegg int &SymIndex = P.first->second; 1251f3f774fSSam Clegg bool IsNew = P.second; 1261f3f774fSSam Clegg if (SymIndex == -1) { 1271f3f774fSSam Clegg SymIndex = SymVector.size(); 1281f3f774fSSam Clegg Trace = true; 1291f3f774fSSam Clegg IsNew = true; 1301f3f774fSSam Clegg } 1311f3f774fSSam Clegg 1321f3f774fSSam Clegg if (!IsNew) 1331f3f774fSSam Clegg return {SymVector[SymIndex], false}; 1341f3f774fSSam Clegg 1351f3f774fSSam Clegg Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 1361f3f774fSSam Clegg Sym->IsUsedInRegularObj = false; 1371f3f774fSSam Clegg Sym->Traced = Trace; 1381f3f774fSSam Clegg SymVector.emplace_back(Sym); 1391f3f774fSSam Clegg return {Sym, true}; 140c94d393aSSam Clegg } 141c94d393aSSam Clegg 142230dc11dSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, 143230dc11dSSam Clegg const InputFile *File) { 1441f3f774fSSam Clegg Symbol *S; 1451f3f774fSSam Clegg bool WasInserted; 1461f3f774fSSam Clegg std::tie(S, WasInserted) = insertName(Name); 1471f3f774fSSam Clegg 1484c2cbfe6SSam Clegg if (!File || File->kind() == InputFile::ObjectKind) 1491f3f774fSSam Clegg S->IsUsedInRegularObj = true; 1501f3f774fSSam Clegg 1511f3f774fSSam Clegg return {S, WasInserted}; 152c94d393aSSam Clegg } 153c94d393aSSam Clegg 154e3498ec5SRui Ueyama static void reportTypeError(const Symbol *Existing, const InputFile *File, 1553876d89aSSam Clegg llvm::wasm::WasmSymbolType Type) { 156e3498ec5SRui Ueyama error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " + 157e3498ec5SRui Ueyama toString(Existing->getWasmType()) + " in " + 1583876d89aSSam Clegg toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) + 1593876d89aSSam Clegg " in " + toString(File)); 160e3498ec5SRui Ueyama } 161e3498ec5SRui Ueyama 1626f4286fbSHeejin Ahn // Check the type of new symbol matches that of the symbol is replacing. 1636540e570SSam Clegg // Returns true if the function types match, false is there is a singature 1646540e570SSam Clegg // mismatch. 1656540e570SSam Clegg bool signatureMatches(FunctionSymbol *Existing, const WasmSignature *NewSig) { 166cefbf9acSSam Clegg if (!NewSig) 1676540e570SSam Clegg return true; 168cefbf9acSSam Clegg 1696540e570SSam Clegg const WasmSignature *OldSig = Existing->Signature; 170cefbf9acSSam Clegg if (!OldSig) { 1716540e570SSam Clegg Existing->Signature = NewSig; 1726540e570SSam Clegg return true; 173cefbf9acSSam Clegg } 174cefbf9acSSam Clegg 1756540e570SSam Clegg return *NewSig == *OldSig; 176e3498ec5SRui Ueyama } 177e3498ec5SRui Ueyama 178e3498ec5SRui Ueyama static void checkGlobalType(const Symbol *Existing, const InputFile *File, 179e3498ec5SRui Ueyama const WasmGlobalType *NewType) { 180e3498ec5SRui Ueyama if (!isa<GlobalSymbol>(Existing)) { 1813876d89aSSam Clegg reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL); 182b8621596SSam Clegg return; 183b8621596SSam Clegg } 184b8621596SSam Clegg 185e3498ec5SRui Ueyama const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType(); 186e3498ec5SRui Ueyama if (*NewType != *OldType) { 187e3498ec5SRui Ueyama error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " + 188e3498ec5SRui Ueyama toString(*OldType) + " in " + toString(Existing->getFile()) + 189e3498ec5SRui Ueyama "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); 190c94d393aSSam Clegg } 19124b3dcd4SSam Clegg } 19224b3dcd4SSam Clegg 193e915a71fSHeejin Ahn static void checkEventType(const Symbol *Existing, const InputFile *File, 194e915a71fSHeejin Ahn const WasmEventType *NewType, 195e915a71fSHeejin Ahn const WasmSignature *NewSig) { 196e915a71fSHeejin Ahn auto ExistingEvent = dyn_cast<EventSymbol>(Existing); 197e915a71fSHeejin Ahn if (!isa<EventSymbol>(Existing)) { 198e915a71fSHeejin Ahn reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT); 199e915a71fSHeejin Ahn return; 200e915a71fSHeejin Ahn } 201e915a71fSHeejin Ahn 202e915a71fSHeejin Ahn const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType(); 203e915a71fSHeejin Ahn const WasmSignature *OldSig = ExistingEvent->Signature; 204e915a71fSHeejin Ahn if (NewType->Attribute != OldType->Attribute) 205e915a71fSHeejin Ahn error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " + 206e915a71fSHeejin Ahn toString(*OldType) + " in " + toString(Existing->getFile()) + 207e915a71fSHeejin Ahn "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); 208e915a71fSHeejin Ahn if (*NewSig != *OldSig) 209e915a71fSHeejin Ahn warn("Event signature mismatch: " + Existing->getName() + 210e915a71fSHeejin Ahn "\n>>> defined as " + toString(*OldSig) + " in " + 211e915a71fSHeejin Ahn toString(Existing->getFile()) + "\n>>> defined as " + 212e915a71fSHeejin Ahn toString(*NewSig) + " in " + toString(File)); 213e915a71fSHeejin Ahn } 214e915a71fSHeejin Ahn 215e3498ec5SRui Ueyama static void checkDataType(const Symbol *Existing, const InputFile *File) { 216e3498ec5SRui Ueyama if (!isa<DataSymbol>(Existing)) 2173876d89aSSam Clegg reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA); 218e3498ec5SRui Ueyama } 219e3498ec5SRui Ueyama 220dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, 221ebda41f8SNicholas Wilson uint32_t Flags, 222ebda41f8SNicholas Wilson InputFunction *Function) { 223e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n"); 224b961abc8SRui Ueyama assert(!find(Name)); 225ebda41f8SNicholas Wilson SyntheticFunctions.emplace_back(Function); 2264c2cbfe6SSam Clegg return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name, 2274c2cbfe6SSam Clegg Flags, nullptr, Function); 22850686856SSam Clegg } 22950686856SSam Clegg 23000245539SSam Clegg DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name, 23100245539SSam Clegg uint32_t Flags) { 232e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n"); 233b961abc8SRui Ueyama assert(!find(Name)); 2344c2cbfe6SSam Clegg return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags); 235c94d393aSSam Clegg } 236c94d393aSSam Clegg 23793102974SSam Clegg DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, 23893102974SSam Clegg InputGlobal *Global) { 239e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global 240e7245b42SNicola Zaghen << "\n"); 241b961abc8SRui Ueyama assert(!find(Name)); 242ebda41f8SNicholas Wilson SyntheticGlobals.emplace_back(Global); 2434c2cbfe6SSam Clegg return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags, 2444c2cbfe6SSam Clegg nullptr, Global); 24593102974SSam Clegg } 24693102974SSam Clegg 247e3498ec5SRui Ueyama static bool shouldReplace(const Symbol *Existing, InputFile *NewFile, 248e3498ec5SRui Ueyama uint32_t NewFlags) { 249c03c9040SRui Ueyama // If existing symbol is undefined, replace it. 250e3498ec5SRui Ueyama if (!Existing->isDefined()) { 251e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 252e3498ec5SRui Ueyama << Existing->getName() << "\n"); 253c03c9040SRui Ueyama return true; 254c03c9040SRui Ueyama } 255c03c9040SRui Ueyama 256c03c9040SRui Ueyama // Now we have two defined symbols. If the new one is weak, we can ignore it. 257c03c9040SRui Ueyama if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 258e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 259c03c9040SRui Ueyama return false; 260c03c9040SRui Ueyama } 261c03c9040SRui Ueyama 262c03c9040SRui Ueyama // If the existing symbol is weak, we should replace it. 263e3498ec5SRui Ueyama if (Existing->isWeak()) { 264e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 265c03c9040SRui Ueyama return true; 266c03c9040SRui Ueyama } 267c03c9040SRui Ueyama 268c03c9040SRui Ueyama // Neither symbol is week. They conflict. 269e3498ec5SRui Ueyama error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + 270e3498ec5SRui Ueyama toString(Existing->getFile()) + "\n>>> defined in " + 271e3498ec5SRui Ueyama toString(NewFile)); 272c03c9040SRui Ueyama return true; 273b8621596SSam Clegg } 27493e559b1SSam Clegg 27593e559b1SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags, 276e3498ec5SRui Ueyama InputFile *File, 277e3498ec5SRui Ueyama InputFunction *Function) { 2788b0b48f3SSam Clegg LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " [" 2798b0b48f3SSam Clegg << (Function ? toString(Function->Signature) : "none") 2808b0b48f3SSam Clegg << "]\n"); 28193e559b1SSam Clegg Symbol *S; 28293e559b1SSam Clegg bool WasInserted; 2834c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 284c729c1b4SSam Clegg 2856540e570SSam Clegg auto Replace = [&](Symbol* Sym) { 2866540e570SSam Clegg // If the new defined function doesn't have signture (i.e. bitcode 2876540e570SSam Clegg // functions) but the old symbol does, then preserve the old signature 2886540e570SSam Clegg const WasmSignature *OldSig = S->getSignature(); 2896540e570SSam Clegg auto* NewSym = replaceSymbol<DefinedFunction>(Sym, Name, Flags, File, Function); 2906540e570SSam Clegg if (!NewSym->Signature) 2916540e570SSam Clegg NewSym->Signature = OldSig; 2926540e570SSam Clegg }; 2936540e570SSam Clegg 294e3498ec5SRui Ueyama if (WasInserted || S->isLazy()) { 2956540e570SSam Clegg Replace(S); 296e3498ec5SRui Ueyama return S; 297e3498ec5SRui Ueyama } 298e3498ec5SRui Ueyama 2996540e570SSam Clegg auto ExistingFunction = dyn_cast<FunctionSymbol>(S); 3006540e570SSam Clegg if (!ExistingFunction) { 3016540e570SSam Clegg reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION); 3026540e570SSam Clegg return S; 3038b0b48f3SSam Clegg } 3046540e570SSam Clegg 3056540e570SSam Clegg if (Function && !signatureMatches(ExistingFunction, &Function->Signature)) { 3066540e570SSam Clegg Symbol* Variant; 3076540e570SSam Clegg if (getFunctionVariant(S, &Function->Signature, File, &Variant)) 3086540e570SSam Clegg // New variant, always replace 3096540e570SSam Clegg Replace(Variant); 3106540e570SSam Clegg else if (shouldReplace(S, File, Flags)) 3116540e570SSam Clegg // Variant already exists, replace it after checking shouldReplace 3126540e570SSam Clegg Replace(Variant); 3136540e570SSam Clegg 3146540e570SSam Clegg // This variant we found take the place in the symbol table as the primary 3156540e570SSam Clegg // variant. 3166540e570SSam Clegg replace(Name, Variant); 3176540e570SSam Clegg return Variant; 3186540e570SSam Clegg } 3196540e570SSam Clegg 3206540e570SSam Clegg // Existing function with matching signature. 3216540e570SSam Clegg if (shouldReplace(S, File, Flags)) 3226540e570SSam Clegg Replace(S); 3236540e570SSam Clegg 32493e559b1SSam Clegg return S; 32593e559b1SSam Clegg } 32693e559b1SSam Clegg 32700245539SSam Clegg Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags, 328e3498ec5SRui Ueyama InputFile *File, InputSegment *Segment, 32993102974SSam Clegg uint32_t Address, uint32_t Size) { 330e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address 331e7245b42SNicola Zaghen << "\n"); 33293e559b1SSam Clegg Symbol *S; 33393e559b1SSam Clegg bool WasInserted; 3344c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 335c729c1b4SSam Clegg 3366540e570SSam Clegg auto Replace = [&]() { 337e3498ec5SRui Ueyama replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); 3386540e570SSam Clegg }; 3396540e570SSam Clegg 3406540e570SSam Clegg if (WasInserted || S->isLazy()) { 3416540e570SSam Clegg Replace(); 342e3498ec5SRui Ueyama return S; 343e3498ec5SRui Ueyama } 344e3498ec5SRui Ueyama 345e3498ec5SRui Ueyama checkDataType(S, File); 346e3498ec5SRui Ueyama 347e3498ec5SRui Ueyama if (shouldReplace(S, File, Flags)) 3486540e570SSam Clegg Replace(); 349c94d393aSSam Clegg return S; 350c94d393aSSam Clegg } 351c94d393aSSam Clegg 35293102974SSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags, 353e3498ec5SRui Ueyama InputFile *File, InputGlobal *Global) { 354e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n"); 3554c2cbfe6SSam Clegg 35693102974SSam Clegg Symbol *S; 35793102974SSam Clegg bool WasInserted; 3584c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 359c729c1b4SSam Clegg 3606540e570SSam Clegg auto Replace = [&]() { 361e3498ec5SRui Ueyama replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); 3626540e570SSam Clegg }; 3636540e570SSam Clegg 3646540e570SSam Clegg if (WasInserted || S->isLazy()) { 3656540e570SSam Clegg Replace(); 36693102974SSam Clegg return S; 36793102974SSam Clegg } 36893102974SSam Clegg 369e3498ec5SRui Ueyama checkGlobalType(S, File, &Global->getType()); 370e3498ec5SRui Ueyama 371e3498ec5SRui Ueyama if (shouldReplace(S, File, Flags)) 3726540e570SSam Clegg Replace(); 373e3498ec5SRui Ueyama return S; 374e3498ec5SRui Ueyama } 375e3498ec5SRui Ueyama 376e915a71fSHeejin Ahn Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags, 377e915a71fSHeejin Ahn InputFile *File, InputEvent *Event) { 378e915a71fSHeejin Ahn LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n"); 379e915a71fSHeejin Ahn 380e915a71fSHeejin Ahn Symbol *S; 381e915a71fSHeejin Ahn bool WasInserted; 382e915a71fSHeejin Ahn std::tie(S, WasInserted) = insert(Name, File); 383e915a71fSHeejin Ahn 3846540e570SSam Clegg auto Replace = [&]() { 385e915a71fSHeejin Ahn replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event); 3866540e570SSam Clegg }; 3876540e570SSam Clegg 3886540e570SSam Clegg if (WasInserted || S->isLazy()) { 3896540e570SSam Clegg Replace(); 390e915a71fSHeejin Ahn return S; 391e915a71fSHeejin Ahn } 392e915a71fSHeejin Ahn 393e915a71fSHeejin Ahn checkEventType(S, File, &Event->getType(), &Event->Signature); 394e915a71fSHeejin Ahn 395e915a71fSHeejin Ahn if (shouldReplace(S, File, Flags)) 3966540e570SSam Clegg Replace(); 397e915a71fSHeejin Ahn return S; 398e915a71fSHeejin Ahn } 399e915a71fSHeejin Ahn 4009b84eeaaSDan Gohman Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName, 4019b84eeaaSDan Gohman StringRef ImportModule, 4027cc07531SSam Clegg uint32_t Flags, InputFile *File, 403e3498ec5SRui Ueyama const WasmSignature *Sig) { 4048b0b48f3SSam Clegg LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << 4058b0b48f3SSam Clegg " [" << (Sig ? toString(*Sig) : "none") << "]\n"); 406c03c9040SRui Ueyama 407c94d393aSSam Clegg Symbol *S; 408c94d393aSSam Clegg bool WasInserted; 4094c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 410c729c1b4SSam Clegg 4116540e570SSam Clegg auto Replace = [&]() { 4129b84eeaaSDan Gohman replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags, 4139b84eeaaSDan Gohman File, Sig); 4146540e570SSam Clegg }; 4156540e570SSam Clegg 4166540e570SSam Clegg if (WasInserted) 4176540e570SSam Clegg Replace(); 418e3498ec5SRui Ueyama else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 419b961abc8SRui Ueyama Lazy->fetch(); 4206540e570SSam Clegg else { 4216540e570SSam Clegg auto ExistingFunction = dyn_cast<FunctionSymbol>(S); 4226540e570SSam Clegg if (!ExistingFunction) { 4236540e570SSam Clegg reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION); 4246540e570SSam Clegg return S; 4256540e570SSam Clegg } 4266540e570SSam Clegg if (!signatureMatches(ExistingFunction, Sig)) 4276540e570SSam Clegg if (getFunctionVariant(S, Sig, File, &S)) 4286540e570SSam Clegg Replace(); 4296540e570SSam Clegg } 430cefbf9acSSam Clegg 431c03c9040SRui Ueyama return S; 432c03c9040SRui Ueyama } 433c03c9040SRui Ueyama 434e3498ec5SRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags, 435e3498ec5SRui Ueyama InputFile *File) { 436e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n"); 43793102974SSam Clegg 438e3498ec5SRui Ueyama Symbol *S; 439e3498ec5SRui Ueyama bool WasInserted; 4404c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 441f989a92dSSam Clegg 442e3498ec5SRui Ueyama if (WasInserted) 443e3498ec5SRui Ueyama replaceSymbol<UndefinedData>(S, Name, Flags, File); 444e3498ec5SRui Ueyama else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 445b961abc8SRui Ueyama Lazy->fetch(); 446e3498ec5SRui Ueyama else if (S->isDefined()) 447e3498ec5SRui Ueyama checkDataType(S, File); 448c94d393aSSam Clegg return S; 449c94d393aSSam Clegg } 450c94d393aSSam Clegg 4519b84eeaaSDan Gohman Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName, 4529b84eeaaSDan Gohman StringRef ImportModule, uint32_t Flags, 453e3498ec5SRui Ueyama InputFile *File, 454e3498ec5SRui Ueyama const WasmGlobalType *Type) { 455e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n"); 456e3498ec5SRui Ueyama 457e3498ec5SRui Ueyama Symbol *S; 458e3498ec5SRui Ueyama bool WasInserted; 4594c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, File); 460c729c1b4SSam Clegg 461e3498ec5SRui Ueyama if (WasInserted) 4629b84eeaaSDan Gohman replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags, 4639b84eeaaSDan Gohman File, Type); 464e3498ec5SRui Ueyama else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 465b961abc8SRui Ueyama Lazy->fetch(); 466e3498ec5SRui Ueyama else if (S->isDefined()) 467e3498ec5SRui Ueyama checkGlobalType(S, File, Type); 468e3498ec5SRui Ueyama return S; 469e3498ec5SRui Ueyama } 470e3498ec5SRui Ueyama 471e3498ec5SRui Ueyama void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) { 472e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); 473c94d393aSSam Clegg StringRef Name = Sym->getName(); 474c03c9040SRui Ueyama 475c94d393aSSam Clegg Symbol *S; 476c94d393aSSam Clegg bool WasInserted; 4774c2cbfe6SSam Clegg std::tie(S, WasInserted) = insert(Name, nullptr); 478c03c9040SRui Ueyama 479c94d393aSSam Clegg if (WasInserted) { 48037b4ee52SSam Clegg replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym); 481c03c9040SRui Ueyama return; 482c03c9040SRui Ueyama } 483c03c9040SRui Ueyama 48437b4ee52SSam Clegg if (!S->isUndefined()) 48537b4ee52SSam Clegg return; 48637b4ee52SSam Clegg 48737b4ee52SSam Clegg // The existing symbol is undefined, load a new one from the archive, 48837b4ee52SSam Clegg // unless the the existing symbol is weak in which case replace the undefined 48937b4ee52SSam Clegg // symbols with a LazySymbol. 49037b4ee52SSam Clegg if (S->isWeak()) { 49137b4ee52SSam Clegg const WasmSignature *OldSig = nullptr; 49237b4ee52SSam Clegg // In the case of an UndefinedFunction we need to preserve the expected 49337b4ee52SSam Clegg // signature. 49437b4ee52SSam Clegg if (auto *F = dyn_cast<UndefinedFunction>(S)) 49537b4ee52SSam Clegg OldSig = F->Signature; 49637b4ee52SSam Clegg LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 49737b4ee52SSam Clegg auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK, 49837b4ee52SSam Clegg File, *Sym); 49937b4ee52SSam Clegg NewSym->Signature = OldSig; 50037b4ee52SSam Clegg return; 50137b4ee52SSam Clegg } 50237b4ee52SSam Clegg 503e7245b42SNicola Zaghen LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 504e3498ec5SRui Ueyama File->addMember(Sym); 505c94d393aSSam Clegg } 506e0f6fcd0SSam Clegg 507c4d9aa1bSNicholas Wilson bool SymbolTable::addComdat(StringRef Name) { 508c4d9aa1bSNicholas Wilson return Comdats.insert(CachedHashStringRef(Name)).second; 509e0f6fcd0SSam Clegg } 5101f3f774fSSam Clegg 5116540e570SSam Clegg // The new signature doesn't match. Create a variant to the symbol with the 5126540e570SSam Clegg // signature encoded in the name and return that instead. These symbols are 5136540e570SSam Clegg // then unified later in handleSymbolVariants. 5146540e570SSam Clegg bool SymbolTable::getFunctionVariant(Symbol* Sym, const WasmSignature *Sig, 5156540e570SSam Clegg const InputFile *File, Symbol **Out) { 516*14bab09eSRichard Trieu LLVM_DEBUG(dbgs() << "getFunctionVariant: " << Sym->getName() << " -> " 517*14bab09eSRichard Trieu << getVariantName(Sym->getName(), *Sig) 5186540e570SSam Clegg << " " << toString(*Sig) << "\n"); 5196540e570SSam Clegg Symbol *Variant = nullptr; 5206540e570SSam Clegg 5216540e570SSam Clegg // Linear search through symbol variants. Should never be more than two 5226540e570SSam Clegg // or three entries here. 5236540e570SSam Clegg auto &Variants = SymVariants[CachedHashStringRef(Sym->getName())]; 5246540e570SSam Clegg if (Variants.size() == 0) 5256540e570SSam Clegg Variants.push_back(Sym); 5266540e570SSam Clegg 5276540e570SSam Clegg for (Symbol* V : Variants) { 5286540e570SSam Clegg if (*V->getSignature() == *Sig) { 5296540e570SSam Clegg Variant = V; 5306540e570SSam Clegg break; 5316540e570SSam Clegg } 5326540e570SSam Clegg } 5336540e570SSam Clegg 5346540e570SSam Clegg bool WasAdded = !Variant; 5356540e570SSam Clegg if (WasAdded) { 5366540e570SSam Clegg // Create a new variant; 5376540e570SSam Clegg LLVM_DEBUG(dbgs() << "added new variant\n"); 5386540e570SSam Clegg Variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 5396540e570SSam Clegg Variants.push_back(Variant); 5406540e570SSam Clegg } else { 5416540e570SSam Clegg LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*Variant) << "\n"); 5426540e570SSam Clegg assert(*Variant->getSignature() == *Sig); 5436540e570SSam Clegg } 5446540e570SSam Clegg 5456540e570SSam Clegg *Out = Variant; 5466540e570SSam Clegg return WasAdded; 5476540e570SSam Clegg } 5486540e570SSam Clegg 5491f3f774fSSam Clegg // Set a flag for --trace-symbol so that we can print out a log message 5501f3f774fSSam Clegg // if a new symbol with the same name is inserted into the symbol table. 5511f3f774fSSam Clegg void SymbolTable::trace(StringRef Name) { 5521f3f774fSSam Clegg SymMap.insert({CachedHashStringRef(Name), -1}); 5531f3f774fSSam Clegg } 554230dc11dSSam Clegg 555230dc11dSSam Clegg static const uint8_t UnreachableFn[] = { 556230dc11dSSam Clegg 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 557230dc11dSSam Clegg 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 558230dc11dSSam Clegg }; 559230dc11dSSam Clegg 560230dc11dSSam Clegg // Replace the given symbol body with an unreachable function. 561230dc11dSSam Clegg // This is used by handleWeakUndefines in order to generate a callable 5626540e570SSam Clegg // equivalent of an undefined function and also handleSymbolVariants for 5636540e570SSam Clegg // undefined functions that don't match the signature of the definition. 564230dc11dSSam Clegg InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym, 565230dc11dSSam Clegg const WasmSignature &Sig, 566230dc11dSSam Clegg StringRef DebugName) { 567230dc11dSSam Clegg auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName); 568230dc11dSSam Clegg Func->setBody(UnreachableFn); 569230dc11dSSam Clegg SyntheticFunctions.emplace_back(Func); 5706540e570SSam Clegg replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr, 5716540e570SSam Clegg Func); 572230dc11dSSam Clegg return Func; 573230dc11dSSam Clegg } 574230dc11dSSam Clegg 575230dc11dSSam Clegg // For weak undefined functions, there may be "call" instructions that reference 576230dc11dSSam Clegg // the symbol. In this case, we need to synthesise a dummy/stub function that 577230dc11dSSam Clegg // will abort at runtime, so that relocations can still provided an operand to 578230dc11dSSam Clegg // the call instruction that passes Wasm validation. 579230dc11dSSam Clegg void SymbolTable::handleWeakUndefines() { 580230dc11dSSam Clegg for (Symbol *Sym : getSymbols()) { 581230dc11dSSam Clegg if (!Sym->isUndefWeak()) 582230dc11dSSam Clegg continue; 583230dc11dSSam Clegg 5846540e570SSam Clegg const WasmSignature *Sig = Sym->getSignature(); 5856540e570SSam Clegg if (!Sig) { 586230dc11dSSam Clegg // It is possible for undefined functions not to have a signature (eg. if 587230dc11dSSam Clegg // added via "--undefined"), but weak undefined ones do have a signature. 5886540e570SSam Clegg // Lazy symbols may not be functions and therefore Sig can still be null 5896540e570SSam Clegg // in some circumstantce. 5906540e570SSam Clegg assert(!isa<FunctionSymbol>(Sym)); 591230dc11dSSam Clegg continue; 5926540e570SSam Clegg } 593230dc11dSSam Clegg 594230dc11dSSam Clegg // Add a synthetic dummy for weak undefined functions. These dummies will 595230dc11dSSam Clegg // be GC'd if not used as the target of any "call" instructions. 596230dc11dSSam Clegg StringRef DebugName = Saver.save("undefined:" + toString(*Sym)); 597230dc11dSSam Clegg InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName); 598230dc11dSSam Clegg // Ensure it compares equal to the null pointer, and so that table relocs 599230dc11dSSam Clegg // don't pull in the stub body (only call-operand relocs should do that). 600230dc11dSSam Clegg Func->setTableIndex(0); 601230dc11dSSam Clegg // Hide our dummy to prevent export. 602230dc11dSSam Clegg Sym->setHidden(true); 603230dc11dSSam Clegg } 604230dc11dSSam Clegg } 6056540e570SSam Clegg 6066540e570SSam Clegg static void reportFunctionSignatureMismatch(StringRef SymName, 6076540e570SSam Clegg FunctionSymbol *A, 6086540e570SSam Clegg FunctionSymbol *B, bool Error) { 6096540e570SSam Clegg std::string msg = ("function signature mismatch: " + SymName + 6106540e570SSam Clegg "\n>>> defined as " + toString(*A->Signature) + " in " + 6116540e570SSam Clegg toString(A->getFile()) + "\n>>> defined as " + 6126540e570SSam Clegg toString(*B->Signature) + " in " + toString(B->getFile())) 6136540e570SSam Clegg .str(); 6146540e570SSam Clegg if (Error) 6156540e570SSam Clegg error(msg); 6166540e570SSam Clegg else 6176540e570SSam Clegg warn(msg); 6186540e570SSam Clegg } 6196540e570SSam Clegg 6206540e570SSam Clegg // Remove any variant symbols that were created due to function signature 6216540e570SSam Clegg // mismatches. 6226540e570SSam Clegg void SymbolTable::handleSymbolVariants() { 6236540e570SSam Clegg for (auto Pair : SymVariants) { 6246540e570SSam Clegg // Push the initial symbol onto the list of variants. 6256540e570SSam Clegg StringRef SymName = Pair.first.val(); 6266540e570SSam Clegg std::vector<Symbol *> &Variants = Pair.second; 6276540e570SSam Clegg 6286540e570SSam Clegg #ifndef NDEBUG 6296540e570SSam Clegg dbgs() << "symbol with (" << Variants.size() 6306540e570SSam Clegg << ") variants: " << SymName << "\n"; 6316540e570SSam Clegg for (auto *S: Variants) { 6326540e570SSam Clegg auto *F = cast<FunctionSymbol>(S); 6336540e570SSam Clegg dbgs() << " variant: " + F->getName() << " " << toString(*F->Signature) << "\n"; 6346540e570SSam Clegg } 6356540e570SSam Clegg #endif 6366540e570SSam Clegg 6376540e570SSam Clegg // Find the one definition. 6386540e570SSam Clegg DefinedFunction *Defined = nullptr; 6396540e570SSam Clegg for (auto *Symbol : Variants) { 6406540e570SSam Clegg if (auto F = dyn_cast<DefinedFunction>(Symbol)) { 6416540e570SSam Clegg Defined = F; 6426540e570SSam Clegg break; 6436540e570SSam Clegg } 6446540e570SSam Clegg } 6456540e570SSam Clegg 6466540e570SSam Clegg // If there are no definitions, and the undefined symbols disagree on 6476540e570SSam Clegg // the signature, there is not we can do since we don't know which one 6486540e570SSam Clegg // to use as the signature on the import. 6496540e570SSam Clegg if (!Defined) { 6506540e570SSam Clegg reportFunctionSignatureMismatch(SymName, 6516540e570SSam Clegg cast<FunctionSymbol>(Variants[0]), 6526540e570SSam Clegg cast<FunctionSymbol>(Variants[1]), true); 6536540e570SSam Clegg return; 6546540e570SSam Clegg } 6556540e570SSam Clegg 6566540e570SSam Clegg for (auto *Symbol : Variants) { 6576540e570SSam Clegg if (Symbol != Defined) { 6586540e570SSam Clegg auto *F = cast<FunctionSymbol>(Symbol); 6596540e570SSam Clegg reportFunctionSignatureMismatch(SymName, F, Defined, false); 6606540e570SSam Clegg StringRef DebugName = Saver.save("unreachable:" + toString(*F)); 6616540e570SSam Clegg replaceWithUnreachable(F, *F->Signature, DebugName); 6626540e570SSam Clegg } 6636540e570SSam Clegg } 6646540e570SSam Clegg } 6656540e570SSam Clegg } 666