1 //===- SymbolTable.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SymbolTable.h" 10 #include "Config.h" 11 #include "InputChunks.h" 12 #include "InputEvent.h" 13 #include "InputGlobal.h" 14 #include "WriterUtils.h" 15 #include "lld/Common/ErrorHandler.h" 16 #include "lld/Common/Memory.h" 17 #include "llvm/ADT/SetVector.h" 18 19 #define DEBUG_TYPE "lld" 20 21 using namespace llvm; 22 using namespace llvm::wasm; 23 using namespace llvm::object; 24 25 namespace lld { 26 namespace wasm { 27 SymbolTable *symtab; 28 29 void SymbolTable::addFile(InputFile *file) { 30 log("Processing: " + toString(file)); 31 32 // .a file 33 if (auto *f = dyn_cast<ArchiveFile>(file)) { 34 f->parse(); 35 return; 36 } 37 38 // .so file 39 if (auto *f = dyn_cast<SharedFile>(file)) { 40 sharedFiles.push_back(f); 41 return; 42 } 43 44 if (config->trace) 45 message(toString(file)); 46 47 // LLVM bitcode file 48 if (auto *f = dyn_cast<BitcodeFile>(file)) { 49 f->parse(); 50 bitcodeFiles.push_back(f); 51 return; 52 } 53 54 // Regular object file 55 auto *f = cast<ObjFile>(file); 56 f->parse(false); 57 objectFiles.push_back(f); 58 } 59 60 // This function is where all the optimizations of link-time 61 // optimization happens. When LTO is in use, some input files are 62 // not in native object file format but in the LLVM bitcode format. 63 // This function compiles bitcode files into a few big native files 64 // using LLVM functions and replaces bitcode symbols with the results. 65 // Because all bitcode files that the program consists of are passed 66 // to the compiler at once, it can do whole-program optimization. 67 void SymbolTable::addCombinedLTOObject() { 68 if (bitcodeFiles.empty()) 69 return; 70 71 // Compile bitcode files and replace bitcode symbols. 72 lto.reset(new BitcodeCompiler); 73 for (BitcodeFile *f : bitcodeFiles) 74 lto->add(*f); 75 76 for (StringRef filename : lto->compile()) { 77 auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), ""); 78 obj->parse(true); 79 objectFiles.push_back(obj); 80 } 81 } 82 83 Symbol *SymbolTable::find(StringRef name) { 84 auto it = symMap.find(CachedHashStringRef(name)); 85 if (it == symMap.end() || it->second == -1) 86 return nullptr; 87 return symVector[it->second]; 88 } 89 90 void SymbolTable::replace(StringRef name, Symbol* sym) { 91 auto it = symMap.find(CachedHashStringRef(name)); 92 symVector[it->second] = sym; 93 } 94 95 std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) { 96 bool trace = false; 97 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 98 int &symIndex = p.first->second; 99 bool isNew = p.second; 100 if (symIndex == -1) { 101 symIndex = symVector.size(); 102 trace = true; 103 isNew = true; 104 } 105 106 if (!isNew) 107 return {symVector[symIndex], false}; 108 109 Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 110 sym->isUsedInRegularObj = false; 111 sym->canInline = true; 112 sym->traced = trace; 113 symVector.emplace_back(sym); 114 return {sym, true}; 115 } 116 117 std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, 118 const InputFile *file) { 119 Symbol *s; 120 bool wasInserted; 121 std::tie(s, wasInserted) = insertName(name); 122 123 if (!file || file->kind() == InputFile::ObjectKind) 124 s->isUsedInRegularObj = true; 125 126 return {s, wasInserted}; 127 } 128 129 static void reportTypeError(const Symbol *existing, const InputFile *file, 130 llvm::wasm::WasmSymbolType type) { 131 error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " + 132 toString(existing->getWasmType()) + " in " + 133 toString(existing->getFile()) + "\n>>> defined as " + toString(type) + 134 " in " + toString(file)); 135 } 136 137 // Check the type of new symbol matches that of the symbol is replacing. 138 // Returns true if the function types match, false is there is a singature 139 // mismatch. 140 static bool signatureMatches(FunctionSymbol *existing, 141 const WasmSignature *newSig) { 142 const WasmSignature *oldSig = existing->signature; 143 144 // If either function is missing a signature (this happend for bitcode 145 // symbols) then assume they match. Any mismatch will be reported later 146 // when the LTO objects are added. 147 if (!newSig || !oldSig) 148 return true; 149 150 return *newSig == *oldSig; 151 } 152 153 static void checkGlobalType(const Symbol *existing, const InputFile *file, 154 const WasmGlobalType *newType) { 155 if (!isa<GlobalSymbol>(existing)) { 156 reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL); 157 return; 158 } 159 160 const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType(); 161 if (*newType != *oldType) { 162 error("Global type mismatch: " + existing->getName() + "\n>>> defined as " + 163 toString(*oldType) + " in " + toString(existing->getFile()) + 164 "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 165 } 166 } 167 168 static void checkEventType(const Symbol *existing, const InputFile *file, 169 const WasmEventType *newType, 170 const WasmSignature *newSig) { 171 auto existingEvent = dyn_cast<EventSymbol>(existing); 172 if (!isa<EventSymbol>(existing)) { 173 reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT); 174 return; 175 } 176 177 const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType(); 178 const WasmSignature *oldSig = existingEvent->signature; 179 if (newType->Attribute != oldType->Attribute) 180 error("Event type mismatch: " + existing->getName() + "\n>>> defined as " + 181 toString(*oldType) + " in " + toString(existing->getFile()) + 182 "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 183 if (*newSig != *oldSig) 184 warn("Event signature mismatch: " + existing->getName() + 185 "\n>>> defined as " + toString(*oldSig) + " in " + 186 toString(existing->getFile()) + "\n>>> defined as " + 187 toString(*newSig) + " in " + toString(file)); 188 } 189 190 static void checkDataType(const Symbol *existing, const InputFile *file) { 191 if (!isa<DataSymbol>(existing)) 192 reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA); 193 } 194 195 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, 196 uint32_t flags, 197 InputFunction *function) { 198 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); 199 assert(!find(name)); 200 syntheticFunctions.emplace_back(function); 201 return replaceSymbol<DefinedFunction>(insertName(name).first, name, 202 flags, nullptr, function); 203 } 204 205 // Adds an optional, linker generated, data symbols. The symbol will only be 206 // added if there is an undefine reference to it, or if it is explictly exported 207 // via the --export flag. Otherwise we don't add the symbol and return nullptr. 208 DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, 209 uint32_t value) { 210 Symbol *s = find(name); 211 if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0)) 212 s = insertName(name).first; 213 else if (!s || s->isDefined()) 214 return nullptr; 215 LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n"); 216 auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN); 217 rtn->setVirtualAddress(value); 218 rtn->referenced = true; 219 return rtn; 220 } 221 222 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, 223 uint32_t flags) { 224 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); 225 assert(!find(name)); 226 return replaceSymbol<DefinedData>(insertName(name).first, name, flags); 227 } 228 229 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, 230 InputGlobal *global) { 231 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global 232 << "\n"); 233 assert(!find(name)); 234 syntheticGlobals.emplace_back(global); 235 return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags, 236 nullptr, global); 237 } 238 239 static bool shouldReplace(const Symbol *existing, InputFile *newFile, 240 uint32_t newFlags) { 241 // If existing symbol is undefined, replace it. 242 if (!existing->isDefined()) { 243 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 244 << existing->getName() << "\n"); 245 return true; 246 } 247 248 // Now we have two defined symbols. If the new one is weak, we can ignore it. 249 if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 250 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 251 return false; 252 } 253 254 // If the existing symbol is weak, we should replace it. 255 if (existing->isWeak()) { 256 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 257 return true; 258 } 259 260 // Neither symbol is week. They conflict. 261 error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + 262 toString(existing->getFile()) + "\n>>> defined in " + 263 toString(newFile)); 264 return true; 265 } 266 267 Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags, 268 InputFile *file, 269 InputFunction *function) { 270 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " [" 271 << (function ? toString(function->signature) : "none") 272 << "]\n"); 273 Symbol *s; 274 bool wasInserted; 275 std::tie(s, wasInserted) = insert(name, file); 276 277 auto replaceSym = [&](Symbol *sym) { 278 // If the new defined function doesn't have signture (i.e. bitcode 279 // functions) but the old symbol does, then preserve the old signature 280 const WasmSignature *oldSig = s->getSignature(); 281 auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function); 282 if (!newSym->signature) 283 newSym->signature = oldSig; 284 }; 285 286 if (wasInserted || s->isLazy()) { 287 replaceSym(s); 288 return s; 289 } 290 291 auto existingFunction = dyn_cast<FunctionSymbol>(s); 292 if (!existingFunction) { 293 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 294 return s; 295 } 296 297 bool checkSig = true; 298 if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) 299 checkSig = ud->isCalledDirectly; 300 301 if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) { 302 Symbol* variant; 303 if (getFunctionVariant(s, &function->signature, file, &variant)) 304 // New variant, always replace 305 replaceSym(variant); 306 else if (shouldReplace(s, file, flags)) 307 // Variant already exists, replace it after checking shouldReplace 308 replaceSym(variant); 309 310 // This variant we found take the place in the symbol table as the primary 311 // variant. 312 replace(name, variant); 313 return variant; 314 } 315 316 // Existing function with matching signature. 317 if (shouldReplace(s, file, flags)) 318 replaceSym(s); 319 320 return s; 321 } 322 323 Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, 324 InputFile *file, InputSegment *segment, 325 uint32_t address, uint32_t size) { 326 LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address 327 << "\n"); 328 Symbol *s; 329 bool wasInserted; 330 std::tie(s, wasInserted) = insert(name, file); 331 332 auto replaceSym = [&]() { 333 replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size); 334 }; 335 336 if (wasInserted || s->isLazy()) { 337 replaceSym(); 338 return s; 339 } 340 341 checkDataType(s, file); 342 343 if (shouldReplace(s, file, flags)) 344 replaceSym(); 345 return s; 346 } 347 348 Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags, 349 InputFile *file, InputGlobal *global) { 350 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n"); 351 352 Symbol *s; 353 bool wasInserted; 354 std::tie(s, wasInserted) = insert(name, file); 355 356 auto replaceSym = [&]() { 357 replaceSymbol<DefinedGlobal>(s, name, flags, file, global); 358 }; 359 360 if (wasInserted || s->isLazy()) { 361 replaceSym(); 362 return s; 363 } 364 365 checkGlobalType(s, file, &global->getType()); 366 367 if (shouldReplace(s, file, flags)) 368 replaceSym(); 369 return s; 370 } 371 372 Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags, 373 InputFile *file, InputEvent *event) { 374 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n"); 375 376 Symbol *s; 377 bool wasInserted; 378 std::tie(s, wasInserted) = insert(name, file); 379 380 auto replaceSym = [&]() { 381 replaceSymbol<DefinedEvent>(s, name, flags, file, event); 382 }; 383 384 if (wasInserted || s->isLazy()) { 385 replaceSym(); 386 return s; 387 } 388 389 checkEventType(s, file, &event->getType(), &event->signature); 390 391 if (shouldReplace(s, file, flags)) 392 replaceSym(); 393 return s; 394 } 395 396 // This function get called when an undefined symbol is added, and there is 397 // already an existing one in the symbols table. In this case we check that 398 // custom 'import-module' and 'import-field' symbol attributes agree. 399 // With LTO these attributes are not avialable when the bitcode is read and only 400 // become available when the LTO object is read. In this case we silently 401 // replace the empty attributes with the valid ones. 402 template <typename T> 403 static void setImportAttributes(T *existing, StringRef importName, 404 StringRef importModule, InputFile *file) { 405 if (!importName.empty()) { 406 if (existing->importName.empty()) 407 existing->importName = importName; 408 if (existing->importName != importName) 409 error("import name mismatch for symbol: " + toString(*existing) + 410 "\n>>> defined as " + existing->importName + " in " + 411 toString(existing->getFile()) + "\n>>> defined as " + importName + 412 " in " + toString(file)); 413 } 414 415 if (!importModule.empty()) { 416 if (existing->importModule.empty()) 417 existing->importModule = importModule; 418 if (existing->importModule != importModule) 419 error("import module mismatch for symbol: " + toString(*existing) + 420 "\n>>> defined as " + existing->importModule + " in " + 421 toString(existing->getFile()) + "\n>>> defined as " + importModule + 422 " in " + toString(file)); 423 } 424 } 425 426 Symbol *SymbolTable::addUndefinedFunction(StringRef name, StringRef importName, 427 StringRef importModule, 428 uint32_t flags, InputFile *file, 429 const WasmSignature *sig, 430 bool isCalledDirectly) { 431 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" 432 << (sig ? toString(*sig) : "none") 433 << "] IsCalledDirectly:" << isCalledDirectly << "\n"); 434 assert(flags & WASM_SYMBOL_UNDEFINED); 435 436 Symbol *s; 437 bool wasInserted; 438 std::tie(s, wasInserted) = insert(name, file); 439 if (s->traced) 440 printTraceSymbolUndefined(name, file); 441 442 auto replaceSym = [&]() { 443 replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags, 444 file, sig, isCalledDirectly); 445 }; 446 447 if (wasInserted) 448 replaceSym(); 449 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 450 lazy->fetch(); 451 else { 452 auto existingFunction = dyn_cast<FunctionSymbol>(s); 453 if (!existingFunction) { 454 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 455 return s; 456 } 457 auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction); 458 if (!existingFunction->signature && sig) 459 existingFunction->signature = sig; 460 if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { 461 // If the existing undefined functions is not called direcltly then let 462 // this one take precedence. Otherwise the existing function is either 463 // direclty called or defined, in which case we need a function variant. 464 if (existingUndefined && !existingUndefined->isCalledDirectly) 465 replaceSym(); 466 else if (getFunctionVariant(s, sig, file, &s)) 467 replaceSym(); 468 } 469 if (existingUndefined) 470 setImportAttributes(existingUndefined, importName, importModule, file); 471 } 472 473 return s; 474 } 475 476 Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, 477 InputFile *file) { 478 LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); 479 assert(flags & WASM_SYMBOL_UNDEFINED); 480 481 Symbol *s; 482 bool wasInserted; 483 std::tie(s, wasInserted) = insert(name, file); 484 if (s->traced) 485 printTraceSymbolUndefined(name, file); 486 487 if (wasInserted) 488 replaceSymbol<UndefinedData>(s, name, flags, file); 489 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 490 lazy->fetch(); 491 else if (s->isDefined()) 492 checkDataType(s, file); 493 return s; 494 } 495 496 Symbol *SymbolTable::addUndefinedGlobal(StringRef name, StringRef importName, 497 StringRef importModule, uint32_t flags, 498 InputFile *file, 499 const WasmGlobalType *type) { 500 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); 501 assert(flags & WASM_SYMBOL_UNDEFINED); 502 503 Symbol *s; 504 bool wasInserted; 505 std::tie(s, wasInserted) = insert(name, file); 506 if (s->traced) 507 printTraceSymbolUndefined(name, file); 508 509 if (wasInserted) 510 replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, 511 file, type); 512 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 513 lazy->fetch(); 514 else if (s->isDefined()) 515 checkGlobalType(s, file, type); 516 return s; 517 } 518 519 void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) { 520 LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n"); 521 StringRef name = sym->getName(); 522 523 Symbol *s; 524 bool wasInserted; 525 std::tie(s, wasInserted) = insertName(name); 526 527 if (wasInserted) { 528 replaceSymbol<LazySymbol>(s, name, 0, file, *sym); 529 return; 530 } 531 532 if (!s->isUndefined()) 533 return; 534 535 // The existing symbol is undefined, load a new one from the archive, 536 // unless the the existing symbol is weak in which case replace the undefined 537 // symbols with a LazySymbol. 538 if (s->isWeak()) { 539 const WasmSignature *oldSig = nullptr; 540 // In the case of an UndefinedFunction we need to preserve the expected 541 // signature. 542 if (auto *f = dyn_cast<UndefinedFunction>(s)) 543 oldSig = f->signature; 544 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 545 auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, 546 file, *sym); 547 newSym->signature = oldSig; 548 return; 549 } 550 551 LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 552 file->addMember(sym); 553 } 554 555 bool SymbolTable::addComdat(StringRef name) { 556 return comdatGroups.insert(CachedHashStringRef(name)).second; 557 } 558 559 // The new signature doesn't match. Create a variant to the symbol with the 560 // signature encoded in the name and return that instead. These symbols are 561 // then unified later in handleSymbolVariants. 562 bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, 563 const InputFile *file, Symbol **out) { 564 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " 565 << " " << toString(*sig) << "\n"); 566 Symbol *variant = nullptr; 567 568 // Linear search through symbol variants. Should never be more than two 569 // or three entries here. 570 auto &variants = symVariants[CachedHashStringRef(sym->getName())]; 571 if (variants.empty()) 572 variants.push_back(sym); 573 574 for (Symbol* v : variants) { 575 if (*v->getSignature() == *sig) { 576 variant = v; 577 break; 578 } 579 } 580 581 bool wasAdded = !variant; 582 if (wasAdded) { 583 // Create a new variant; 584 LLVM_DEBUG(dbgs() << "added new variant\n"); 585 variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 586 variants.push_back(variant); 587 } else { 588 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); 589 assert(*variant->getSignature() == *sig); 590 } 591 592 *out = variant; 593 return wasAdded; 594 } 595 596 // Set a flag for --trace-symbol so that we can print out a log message 597 // if a new symbol with the same name is inserted into the symbol table. 598 void SymbolTable::trace(StringRef name) { 599 symMap.insert({CachedHashStringRef(name), -1}); 600 } 601 602 void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { 603 // Swap symbols as instructed by -wrap. 604 int &origIdx = symMap[CachedHashStringRef(sym->getName())]; 605 int &realIdx= symMap[CachedHashStringRef(real->getName())]; 606 int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; 607 LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); 608 609 // Anyone looking up __real symbols should get the original 610 realIdx = origIdx; 611 // Anyone looking up the original should get the __wrap symbol 612 origIdx = wrapIdx; 613 } 614 615 static const uint8_t unreachableFn[] = { 616 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 617 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 618 }; 619 620 // Replace the given symbol body with an unreachable function. 621 // This is used by handleWeakUndefines in order to generate a callable 622 // equivalent of an undefined function and also handleSymbolVariants for 623 // undefined functions that don't match the signature of the definition. 624 InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, 625 const WasmSignature &sig, 626 StringRef debugName) { 627 auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); 628 func->setBody(unreachableFn); 629 syntheticFunctions.emplace_back(func); 630 replaceSymbol<DefinedFunction>(sym, sym->getName(), sym->getFlags(), nullptr, 631 func); 632 return func; 633 } 634 635 // For weak undefined functions, there may be "call" instructions that reference 636 // the symbol. In this case, we need to synthesise a dummy/stub function that 637 // will abort at runtime, so that relocations can still provided an operand to 638 // the call instruction that passes Wasm validation. 639 void SymbolTable::handleWeakUndefines() { 640 for (Symbol *sym : getSymbols()) { 641 if (!sym->isUndefWeak()) 642 continue; 643 644 const WasmSignature *sig = sym->getSignature(); 645 if (!sig) { 646 // It is possible for undefined functions not to have a signature (eg. if 647 // added via "--undefined"), but weak undefined ones do have a signature. 648 // Lazy symbols may not be functions and therefore Sig can still be null 649 // in some circumstantce. 650 assert(!isa<FunctionSymbol>(sym)); 651 continue; 652 } 653 654 // Add a synthetic dummy for weak undefined functions. These dummies will 655 // be GC'd if not used as the target of any "call" instructions. 656 StringRef debugName = saver.save("undefined:" + toString(*sym)); 657 InputFunction* func = replaceWithUnreachable(sym, *sig, debugName); 658 // Ensure it compares equal to the null pointer, and so that table relocs 659 // don't pull in the stub body (only call-operand relocs should do that). 660 func->setTableIndex(0); 661 // Hide our dummy to prevent export. 662 sym->setHidden(true); 663 } 664 } 665 666 static void reportFunctionSignatureMismatch(StringRef symName, 667 FunctionSymbol *a, 668 FunctionSymbol *b, bool isError) { 669 std::string msg = ("function signature mismatch: " + symName + 670 "\n>>> defined as " + toString(*a->signature) + " in " + 671 toString(a->getFile()) + "\n>>> defined as " + 672 toString(*b->signature) + " in " + toString(b->getFile())) 673 .str(); 674 if (isError) 675 error(msg); 676 else 677 warn(msg); 678 } 679 680 // Remove any variant symbols that were created due to function signature 681 // mismatches. 682 void SymbolTable::handleSymbolVariants() { 683 for (auto pair : symVariants) { 684 // Push the initial symbol onto the list of variants. 685 StringRef symName = pair.first.val(); 686 std::vector<Symbol *> &variants = pair.second; 687 688 #ifndef NDEBUG 689 LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() 690 << ") variants: " << symName << "\n"); 691 for (auto *s: variants) { 692 auto *f = cast<FunctionSymbol>(s); 693 LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " 694 << toString(*f->signature) << "\n"); 695 } 696 #endif 697 698 // Find the one definition. 699 DefinedFunction *defined = nullptr; 700 for (auto *symbol : variants) { 701 if (auto f = dyn_cast<DefinedFunction>(symbol)) { 702 defined = f; 703 break; 704 } 705 } 706 707 // If there are no definitions, and the undefined symbols disagree on 708 // the signature, there is not we can do since we don't know which one 709 // to use as the signature on the import. 710 if (!defined) { 711 reportFunctionSignatureMismatch(symName, 712 cast<FunctionSymbol>(variants[0]), 713 cast<FunctionSymbol>(variants[1]), true); 714 return; 715 } 716 717 for (auto *symbol : variants) { 718 if (symbol != defined) { 719 auto *f = cast<FunctionSymbol>(symbol); 720 reportFunctionSignatureMismatch(symName, f, defined, false); 721 StringRef debugName = saver.save("unreachable:" + toString(*f)); 722 replaceWithUnreachable(f, *f->signature, debugName); 723 } 724 } 725 } 726 } 727 728 } // namespace wasm 729 } // namespace lld 730