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