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 "InputElement.h" 13 #include "WriterUtils.h" 14 #include "lld/Common/ErrorHandler.h" 15 #include "lld/Common/Memory.h" 16 #include "llvm/ADT/SetVector.h" 17 18 #define DEBUG_TYPE "lld" 19 20 using namespace llvm; 21 using namespace llvm::wasm; 22 using namespace llvm::object; 23 24 namespace lld { 25 namespace wasm { 26 SymbolTable *symtab; 27 28 void SymbolTable::addFile(InputFile *file) { 29 log("Processing: " + toString(file)); 30 31 // .a file 32 if (auto *f = dyn_cast<ArchiveFile>(file)) { 33 f->parse(); 34 return; 35 } 36 37 // .so file 38 if (auto *f = dyn_cast<SharedFile>(file)) { 39 sharedFiles.push_back(f); 40 return; 41 } 42 43 if (config->trace) 44 message(toString(file)); 45 46 // LLVM bitcode file 47 if (auto *f = dyn_cast<BitcodeFile>(file)) { 48 f->parse(); 49 bitcodeFiles.push_back(f); 50 return; 51 } 52 53 // Regular object file 54 auto *f = cast<ObjFile>(file); 55 f->parse(false); 56 objectFiles.push_back(f); 57 } 58 59 // This function is where all the optimizations of link-time 60 // optimization happens. When LTO is in use, some input files are 61 // not in native object file format but in the LLVM bitcode format. 62 // This function compiles bitcode files into a few big native files 63 // using LLVM functions and replaces bitcode symbols with the results. 64 // Because all bitcode files that the program consists of are passed 65 // to the compiler at once, it can do whole-program optimization. 66 void SymbolTable::addCombinedLTOObject() { 67 // Prevent further LTO objects being included 68 BitcodeFile::doneLTO = true; 69 70 if (bitcodeFiles.empty()) 71 return; 72 73 // Compile bitcode files and replace bitcode symbols. 74 lto.reset(new BitcodeCompiler); 75 for (BitcodeFile *f : bitcodeFiles) 76 lto->add(*f); 77 78 for (StringRef filename : lto->compile()) { 79 auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), ""); 80 obj->parse(true); 81 objectFiles.push_back(obj); 82 } 83 } 84 85 Symbol *SymbolTable::find(StringRef name) { 86 auto it = symMap.find(CachedHashStringRef(name)); 87 if (it == symMap.end() || it->second == -1) 88 return nullptr; 89 return symVector[it->second]; 90 } 91 92 void SymbolTable::replace(StringRef name, Symbol* sym) { 93 auto it = symMap.find(CachedHashStringRef(name)); 94 symVector[it->second] = sym; 95 } 96 97 std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) { 98 bool trace = false; 99 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 100 int &symIndex = p.first->second; 101 bool isNew = p.second; 102 if (symIndex == -1) { 103 symIndex = symVector.size(); 104 trace = true; 105 isNew = true; 106 } 107 108 if (!isNew) 109 return {symVector[symIndex], false}; 110 111 Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 112 sym->isUsedInRegularObj = false; 113 sym->canInline = true; 114 sym->traced = trace; 115 sym->forceExport = false; 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 signature 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 checkTableType(const Symbol *existing, const InputFile *file, 194 const WasmTableType *newType) { 195 if (!isa<TableSymbol>(existing)) { 196 reportTypeError(existing, file, WASM_SYMBOL_TYPE_TABLE); 197 return; 198 } 199 200 const WasmTableType *oldType = cast<TableSymbol>(existing)->getTableType(); 201 if (newType->ElemType != oldType->ElemType) { 202 error("Table type mismatch: " + existing->getName() + "\n>>> defined as " + 203 toString(*oldType) + " in " + toString(existing->getFile()) + 204 "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 205 } 206 // FIXME: No assertions currently on the limits. 207 } 208 209 static void checkDataType(const Symbol *existing, const InputFile *file) { 210 if (!isa<DataSymbol>(existing)) 211 reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA); 212 } 213 214 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, 215 uint32_t flags, 216 InputFunction *function) { 217 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); 218 assert(!find(name)); 219 syntheticFunctions.emplace_back(function); 220 return replaceSymbol<DefinedFunction>(insertName(name).first, name, 221 flags, nullptr, function); 222 } 223 224 // Adds an optional, linker generated, data symbol. The symbol will only be 225 // added if there is an undefine reference to it, or if it is explicitly 226 // exported via the --export flag. Otherwise we don't add the symbol and return 227 // nullptr. 228 DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, 229 uint64_t value) { 230 Symbol *s = find(name); 231 if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0)) 232 s = insertName(name).first; 233 else if (!s || s->isDefined()) 234 return nullptr; 235 LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n"); 236 auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN); 237 rtn->setVirtualAddress(value); 238 rtn->referenced = true; 239 return rtn; 240 } 241 242 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, 243 uint32_t flags) { 244 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); 245 assert(!find(name)); 246 return replaceSymbol<DefinedData>(insertName(name).first, name, flags); 247 } 248 249 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, 250 InputGlobal *global) { 251 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global 252 << "\n"); 253 assert(!find(name)); 254 syntheticGlobals.emplace_back(global); 255 return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags, 256 nullptr, global); 257 } 258 259 DefinedGlobal *SymbolTable::addOptionalGlobalSymbol(StringRef name, 260 InputGlobal *global) { 261 LLVM_DEBUG(dbgs() << "addOptionalGlobalSymbol: " << name << " -> " << global 262 << "\n"); 263 Symbol *s = find(name); 264 if (!s || s->isDefined()) 265 return nullptr; 266 syntheticGlobals.emplace_back(global); 267 return replaceSymbol<DefinedGlobal>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN, 268 nullptr, global); 269 } 270 271 DefinedTable *SymbolTable::addSyntheticTable(StringRef name, uint32_t flags, 272 InputTable *table) { 273 LLVM_DEBUG(dbgs() << "addSyntheticTable: " << name << " -> " << table 274 << "\n"); 275 Symbol *s = find(name); 276 assert(!s || s->isUndefined()); 277 if (!s) 278 s = insertName(name).first; 279 syntheticTables.emplace_back(table); 280 return replaceSymbol<DefinedTable>(s, name, flags, nullptr, table); 281 } 282 283 static bool shouldReplace(const Symbol *existing, InputFile *newFile, 284 uint32_t newFlags) { 285 // If existing symbol is undefined, replace it. 286 if (!existing->isDefined()) { 287 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 288 << existing->getName() << "\n"); 289 return true; 290 } 291 292 // Now we have two defined symbols. If the new one is weak, we can ignore it. 293 if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 294 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 295 return false; 296 } 297 298 // If the existing symbol is weak, we should replace it. 299 if (existing->isWeak()) { 300 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 301 return true; 302 } 303 304 // Neither symbol is week. They conflict. 305 error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + 306 toString(existing->getFile()) + "\n>>> defined in " + 307 toString(newFile)); 308 return true; 309 } 310 311 Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags, 312 InputFile *file, 313 InputFunction *function) { 314 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " [" 315 << (function ? toString(function->signature) : "none") 316 << "]\n"); 317 Symbol *s; 318 bool wasInserted; 319 std::tie(s, wasInserted) = insert(name, file); 320 321 auto replaceSym = [&](Symbol *sym) { 322 // If the new defined function doesn't have signature (i.e. bitcode 323 // functions) but the old symbol does, then preserve the old signature 324 const WasmSignature *oldSig = s->getSignature(); 325 auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function); 326 if (!newSym->signature) 327 newSym->signature = oldSig; 328 }; 329 330 if (wasInserted || s->isLazy()) { 331 replaceSym(s); 332 return s; 333 } 334 335 auto existingFunction = dyn_cast<FunctionSymbol>(s); 336 if (!existingFunction) { 337 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 338 return s; 339 } 340 341 bool checkSig = true; 342 if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) 343 checkSig = ud->isCalledDirectly; 344 345 if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) { 346 Symbol* variant; 347 if (getFunctionVariant(s, &function->signature, file, &variant)) 348 // New variant, always replace 349 replaceSym(variant); 350 else if (shouldReplace(s, file, flags)) 351 // Variant already exists, replace it after checking shouldReplace 352 replaceSym(variant); 353 354 // This variant we found take the place in the symbol table as the primary 355 // variant. 356 replace(name, variant); 357 return variant; 358 } 359 360 // Existing function with matching signature. 361 if (shouldReplace(s, file, flags)) 362 replaceSym(s); 363 364 return s; 365 } 366 367 Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, 368 InputFile *file, InputSegment *segment, 369 uint64_t address, uint64_t size) { 370 LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address 371 << "\n"); 372 Symbol *s; 373 bool wasInserted; 374 std::tie(s, wasInserted) = insert(name, file); 375 376 auto replaceSym = [&]() { 377 replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size); 378 }; 379 380 if (wasInserted || s->isLazy()) { 381 replaceSym(); 382 return s; 383 } 384 385 checkDataType(s, file); 386 387 if (shouldReplace(s, file, flags)) 388 replaceSym(); 389 return s; 390 } 391 392 Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags, 393 InputFile *file, InputGlobal *global) { 394 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n"); 395 396 Symbol *s; 397 bool wasInserted; 398 std::tie(s, wasInserted) = insert(name, file); 399 400 auto replaceSym = [&]() { 401 replaceSymbol<DefinedGlobal>(s, name, flags, file, global); 402 }; 403 404 if (wasInserted || s->isLazy()) { 405 replaceSym(); 406 return s; 407 } 408 409 checkGlobalType(s, file, &global->getType()); 410 411 if (shouldReplace(s, file, flags)) 412 replaceSym(); 413 return s; 414 } 415 416 Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags, 417 InputFile *file, InputEvent *event) { 418 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n"); 419 420 Symbol *s; 421 bool wasInserted; 422 std::tie(s, wasInserted) = insert(name, file); 423 424 auto replaceSym = [&]() { 425 replaceSymbol<DefinedEvent>(s, name, flags, file, event); 426 }; 427 428 if (wasInserted || s->isLazy()) { 429 replaceSym(); 430 return s; 431 } 432 433 checkEventType(s, file, &event->getType(), &event->signature); 434 435 if (shouldReplace(s, file, flags)) 436 replaceSym(); 437 return s; 438 } 439 440 Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags, 441 InputFile *file, InputTable *table) { 442 LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n"); 443 444 Symbol *s; 445 bool wasInserted; 446 std::tie(s, wasInserted) = insert(name, file); 447 448 auto replaceSym = [&]() { 449 replaceSymbol<DefinedTable>(s, name, flags, file, table); 450 }; 451 452 if (wasInserted || s->isLazy()) { 453 replaceSym(); 454 return s; 455 } 456 457 checkTableType(s, file, &table->getType()); 458 459 if (shouldReplace(s, file, flags)) 460 replaceSym(); 461 return s; 462 } 463 464 // This function get called when an undefined symbol is added, and there is 465 // already an existing one in the symbols table. In this case we check that 466 // custom 'import-module' and 'import-field' symbol attributes agree. 467 // With LTO these attributes are not available when the bitcode is read and only 468 // become available when the LTO object is read. In this case we silently 469 // replace the empty attributes with the valid ones. 470 template <typename T> 471 static void setImportAttributes(T *existing, Optional<StringRef> importName, 472 Optional<StringRef> importModule, 473 uint32_t flags, InputFile *file) { 474 if (importName) { 475 if (!existing->importName) 476 existing->importName = importName; 477 if (existing->importName != importName) 478 error("import name mismatch for symbol: " + toString(*existing) + 479 "\n>>> defined as " + *existing->importName + " in " + 480 toString(existing->getFile()) + "\n>>> defined as " + *importName + 481 " in " + toString(file)); 482 } 483 484 if (importModule) { 485 if (!existing->importModule) 486 existing->importModule = importModule; 487 if (existing->importModule != importModule) 488 error("import module mismatch for symbol: " + toString(*existing) + 489 "\n>>> defined as " + *existing->importModule + " in " + 490 toString(existing->getFile()) + "\n>>> defined as " + 491 *importModule + " in " + toString(file)); 492 } 493 494 // Update symbol binding, if the existing symbol is weak 495 uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK; 496 if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) { 497 existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding; 498 } 499 } 500 501 Symbol *SymbolTable::addUndefinedFunction(StringRef name, 502 Optional<StringRef> importName, 503 Optional<StringRef> importModule, 504 uint32_t flags, InputFile *file, 505 const WasmSignature *sig, 506 bool isCalledDirectly) { 507 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" 508 << (sig ? toString(*sig) : "none") 509 << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x" 510 << utohexstr(flags) << "\n"); 511 assert(flags & WASM_SYMBOL_UNDEFINED); 512 513 Symbol *s; 514 bool wasInserted; 515 std::tie(s, wasInserted) = insert(name, file); 516 if (s->traced) 517 printTraceSymbolUndefined(name, file); 518 519 auto replaceSym = [&]() { 520 replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags, 521 file, sig, isCalledDirectly); 522 }; 523 524 if (wasInserted) { 525 replaceSym(); 526 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 527 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 528 lazy->setWeak(); 529 lazy->signature = sig; 530 } else { 531 lazy->fetch(); 532 } 533 } else { 534 auto existingFunction = dyn_cast<FunctionSymbol>(s); 535 if (!existingFunction) { 536 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 537 return s; 538 } 539 if (!existingFunction->signature && sig) 540 existingFunction->signature = sig; 541 auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction); 542 if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { 543 // If the existing undefined functions is not called directly then let 544 // this one take precedence. Otherwise the existing function is either 545 // directly called or defined, in which case we need a function variant. 546 if (existingUndefined && !existingUndefined->isCalledDirectly) 547 replaceSym(); 548 else if (getFunctionVariant(s, sig, file, &s)) 549 replaceSym(); 550 } 551 if (existingUndefined) 552 setImportAttributes(existingUndefined, importName, importModule, flags, 553 file); 554 } 555 556 return s; 557 } 558 559 Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, 560 InputFile *file) { 561 LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); 562 assert(flags & WASM_SYMBOL_UNDEFINED); 563 564 Symbol *s; 565 bool wasInserted; 566 std::tie(s, wasInserted) = insert(name, file); 567 if (s->traced) 568 printTraceSymbolUndefined(name, file); 569 570 if (wasInserted) { 571 replaceSymbol<UndefinedData>(s, name, flags, file); 572 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 573 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) 574 lazy->setWeak(); 575 else 576 lazy->fetch(); 577 } else if (s->isDefined()) { 578 checkDataType(s, file); 579 } 580 return s; 581 } 582 583 Symbol *SymbolTable::addUndefinedGlobal(StringRef name, 584 Optional<StringRef> importName, 585 Optional<StringRef> importModule, 586 uint32_t flags, InputFile *file, 587 const WasmGlobalType *type) { 588 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); 589 assert(flags & WASM_SYMBOL_UNDEFINED); 590 591 Symbol *s; 592 bool wasInserted; 593 std::tie(s, wasInserted) = insert(name, file); 594 if (s->traced) 595 printTraceSymbolUndefined(name, file); 596 597 if (wasInserted) 598 replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, 599 file, type); 600 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 601 lazy->fetch(); 602 else if (s->isDefined()) 603 checkGlobalType(s, file, type); 604 return s; 605 } 606 607 Symbol *SymbolTable::addUndefinedTable(StringRef name, 608 Optional<StringRef> importName, 609 Optional<StringRef> importModule, 610 uint32_t flags, InputFile *file, 611 const WasmTableType *type) { 612 LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n"); 613 assert(flags & WASM_SYMBOL_UNDEFINED); 614 615 Symbol *s; 616 bool wasInserted; 617 std::tie(s, wasInserted) = insert(name, file); 618 if (s->traced) 619 printTraceSymbolUndefined(name, file); 620 621 if (wasInserted) 622 replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags, 623 file, type); 624 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 625 lazy->fetch(); 626 else if (s->isDefined()) 627 checkTableType(s, file, type); 628 return s; 629 } 630 631 void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) { 632 LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n"); 633 StringRef name = sym->getName(); 634 635 Symbol *s; 636 bool wasInserted; 637 std::tie(s, wasInserted) = insertName(name); 638 639 if (wasInserted) { 640 replaceSymbol<LazySymbol>(s, name, 0, file, *sym); 641 return; 642 } 643 644 if (!s->isUndefined()) 645 return; 646 647 // The existing symbol is undefined, load a new one from the archive, 648 // unless the existing symbol is weak in which case replace the undefined 649 // symbols with a LazySymbol. 650 if (s->isWeak()) { 651 const WasmSignature *oldSig = nullptr; 652 // In the case of an UndefinedFunction we need to preserve the expected 653 // signature. 654 if (auto *f = dyn_cast<UndefinedFunction>(s)) 655 oldSig = f->signature; 656 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 657 auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, 658 file, *sym); 659 newSym->signature = oldSig; 660 return; 661 } 662 663 LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 664 file->addMember(sym); 665 } 666 667 bool SymbolTable::addComdat(StringRef name) { 668 return comdatGroups.insert(CachedHashStringRef(name)).second; 669 } 670 671 // The new signature doesn't match. Create a variant to the symbol with the 672 // signature encoded in the name and return that instead. These symbols are 673 // then unified later in handleSymbolVariants. 674 bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, 675 const InputFile *file, Symbol **out) { 676 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " 677 << " " << toString(*sig) << "\n"); 678 Symbol *variant = nullptr; 679 680 // Linear search through symbol variants. Should never be more than two 681 // or three entries here. 682 auto &variants = symVariants[CachedHashStringRef(sym->getName())]; 683 if (variants.empty()) 684 variants.push_back(sym); 685 686 for (Symbol* v : variants) { 687 if (*v->getSignature() == *sig) { 688 variant = v; 689 break; 690 } 691 } 692 693 bool wasAdded = !variant; 694 if (wasAdded) { 695 // Create a new variant; 696 LLVM_DEBUG(dbgs() << "added new variant\n"); 697 variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 698 variant->isUsedInRegularObj = 699 !file || file->kind() == InputFile::ObjectKind; 700 variant->canInline = true; 701 variant->traced = false; 702 variant->forceExport = false; 703 variants.push_back(variant); 704 } else { 705 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); 706 assert(*variant->getSignature() == *sig); 707 } 708 709 *out = variant; 710 return wasAdded; 711 } 712 713 // Set a flag for --trace-symbol so that we can print out a log message 714 // if a new symbol with the same name is inserted into the symbol table. 715 void SymbolTable::trace(StringRef name) { 716 symMap.insert({CachedHashStringRef(name), -1}); 717 } 718 719 void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { 720 // Swap symbols as instructed by -wrap. 721 int &origIdx = symMap[CachedHashStringRef(sym->getName())]; 722 int &realIdx= symMap[CachedHashStringRef(real->getName())]; 723 int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; 724 LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); 725 726 // Anyone looking up __real symbols should get the original 727 realIdx = origIdx; 728 // Anyone looking up the original should get the __wrap symbol 729 origIdx = wrapIdx; 730 } 731 732 static const uint8_t unreachableFn[] = { 733 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 734 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 735 }; 736 737 // Replace the given symbol body with an unreachable function. 738 // This is used by handleWeakUndefines in order to generate a callable 739 // equivalent of an undefined function and also handleSymbolVariants for 740 // undefined functions that don't match the signature of the definition. 741 InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, 742 const WasmSignature &sig, 743 StringRef debugName) { 744 auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); 745 func->setBody(unreachableFn); 746 syntheticFunctions.emplace_back(func); 747 // Mark new symbols as local. For relocatable output we don't want them 748 // to be exported outside the object file. 749 replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL, 750 nullptr, func); 751 // Ensure the stub function doesn't get a table entry. Its address 752 // should always compare equal to the null pointer. 753 sym->isStub = true; 754 return func; 755 } 756 757 void SymbolTable::replaceWithUndefined(Symbol *sym) { 758 // Add a synthetic dummy for weak undefined functions. These dummies will 759 // be GC'd if not used as the target of any "call" instructions. 760 StringRef debugName = saver.save("undefined_weak:" + toString(*sym)); 761 replaceWithUnreachable(sym, *sym->getSignature(), debugName); 762 // Hide our dummy to prevent export. 763 sym->setHidden(true); 764 } 765 766 // For weak undefined functions, there may be "call" instructions that reference 767 // the symbol. In this case, we need to synthesise a dummy/stub function that 768 // will abort at runtime, so that relocations can still provided an operand to 769 // the call instruction that passes Wasm validation. 770 void SymbolTable::handleWeakUndefines() { 771 for (Symbol *sym : getSymbols()) { 772 if (sym->isUndefWeak()) { 773 if (sym->getSignature()) { 774 replaceWithUndefined(sym); 775 } else { 776 // It is possible for undefined functions not to have a signature (eg. 777 // if added via "--undefined"), but weak undefined ones do have a 778 // signature. Lazy symbols may not be functions and therefore Sig can 779 // still be null in some circumstance. 780 assert(!isa<FunctionSymbol>(sym)); 781 } 782 } 783 } 784 } 785 786 DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) { 787 if (stubFunctions.count(sig)) 788 return stubFunctions[sig]; 789 LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n"); 790 auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>()); 791 sym->isUsedInRegularObj = true; 792 sym->canInline = true; 793 sym->traced = false; 794 sym->forceExport = false; 795 sym->signature = &sig; 796 replaceSymbol<DefinedFunction>( 797 sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr); 798 replaceWithUnreachable(sym, sig, "undefined_stub"); 799 stubFunctions[sig] = sym; 800 return sym; 801 } 802 803 static void reportFunctionSignatureMismatch(StringRef symName, 804 FunctionSymbol *a, 805 FunctionSymbol *b, bool isError) { 806 std::string msg = ("function signature mismatch: " + symName + 807 "\n>>> defined as " + toString(*a->signature) + " in " + 808 toString(a->getFile()) + "\n>>> defined as " + 809 toString(*b->signature) + " in " + toString(b->getFile())) 810 .str(); 811 if (isError) 812 error(msg); 813 else 814 warn(msg); 815 } 816 817 // Remove any variant symbols that were created due to function signature 818 // mismatches. 819 void SymbolTable::handleSymbolVariants() { 820 for (auto pair : symVariants) { 821 // Push the initial symbol onto the list of variants. 822 StringRef symName = pair.first.val(); 823 std::vector<Symbol *> &variants = pair.second; 824 825 #ifndef NDEBUG 826 LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() 827 << ") variants: " << symName << "\n"); 828 for (auto *s: variants) { 829 auto *f = cast<FunctionSymbol>(s); 830 LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " 831 << toString(*f->signature) << "\n"); 832 } 833 #endif 834 835 // Find the one definition. 836 DefinedFunction *defined = nullptr; 837 for (auto *symbol : variants) { 838 if (auto f = dyn_cast<DefinedFunction>(symbol)) { 839 defined = f; 840 break; 841 } 842 } 843 844 // If there are no definitions, and the undefined symbols disagree on 845 // the signature, there is not we can do since we don't know which one 846 // to use as the signature on the import. 847 if (!defined) { 848 reportFunctionSignatureMismatch(symName, 849 cast<FunctionSymbol>(variants[0]), 850 cast<FunctionSymbol>(variants[1]), true); 851 return; 852 } 853 854 for (auto *symbol : variants) { 855 if (symbol != defined) { 856 auto *f = cast<FunctionSymbol>(symbol); 857 reportFunctionSignatureMismatch(symName, f, defined, false); 858 StringRef debugName = saver.save("signature_mismatch:" + toString(*f)); 859 replaceWithUnreachable(f, *f->signature, debugName); 860 } 861 } 862 } 863 } 864 865 } // namespace wasm 866 } // namespace lld 867