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