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 checkTagType(const Symbol *existing, const InputFile *file, 172 const WasmTagType *newType, 173 const WasmSignature *newSig) { 174 const auto *existingTag = dyn_cast<TagSymbol>(existing); 175 if (!isa<TagSymbol>(existing)) { 176 reportTypeError(existing, file, WASM_SYMBOL_TYPE_TAG); 177 return; 178 } 179 180 const WasmTagType *oldType = cast<TagSymbol>(existing)->getTagType(); 181 const WasmSignature *oldSig = existingTag->signature; 182 if (newType->Attribute != oldType->Attribute) 183 error("Tag 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("Tag 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->setVA(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, InputChunk *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::addDefinedTag(StringRef name, uint32_t flags, 417 InputFile *file, InputTag *tag) { 418 LLVM_DEBUG(dbgs() << "addDefinedTag:" << name << "\n"); 419 420 Symbol *s; 421 bool wasInserted; 422 std::tie(s, wasInserted) = insert(name, file); 423 424 auto replaceSym = [&]() { 425 replaceSymbol<DefinedTag>(s, name, flags, file, tag); 426 }; 427 428 if (wasInserted || s->isLazy()) { 429 replaceSym(); 430 return s; 431 } 432 433 checkTagType(s, file, &tag->getType(), &tag->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 if (isCalledDirectly) 555 existingUndefined->isCalledDirectly = true; 556 } 557 } 558 559 return s; 560 } 561 562 Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, 563 InputFile *file) { 564 LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); 565 assert(flags & WASM_SYMBOL_UNDEFINED); 566 567 Symbol *s; 568 bool wasInserted; 569 std::tie(s, wasInserted) = insert(name, file); 570 if (s->traced) 571 printTraceSymbolUndefined(name, file); 572 573 if (wasInserted) { 574 replaceSymbol<UndefinedData>(s, name, flags, file); 575 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 576 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) 577 lazy->setWeak(); 578 else 579 lazy->fetch(); 580 } else if (s->isDefined()) { 581 checkDataType(s, file); 582 } 583 return s; 584 } 585 586 Symbol *SymbolTable::addUndefinedGlobal(StringRef name, 587 Optional<StringRef> importName, 588 Optional<StringRef> importModule, 589 uint32_t flags, InputFile *file, 590 const WasmGlobalType *type) { 591 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); 592 assert(flags & WASM_SYMBOL_UNDEFINED); 593 594 Symbol *s; 595 bool wasInserted; 596 std::tie(s, wasInserted) = insert(name, file); 597 if (s->traced) 598 printTraceSymbolUndefined(name, file); 599 600 if (wasInserted) 601 replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, 602 file, type); 603 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 604 lazy->fetch(); 605 else if (s->isDefined()) 606 checkGlobalType(s, file, type); 607 return s; 608 } 609 610 Symbol *SymbolTable::addUndefinedTable(StringRef name, 611 Optional<StringRef> importName, 612 Optional<StringRef> importModule, 613 uint32_t flags, InputFile *file, 614 const WasmTableType *type) { 615 LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n"); 616 assert(flags & WASM_SYMBOL_UNDEFINED); 617 618 Symbol *s; 619 bool wasInserted; 620 std::tie(s, wasInserted) = insert(name, file); 621 if (s->traced) 622 printTraceSymbolUndefined(name, file); 623 624 if (wasInserted) 625 replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags, 626 file, type); 627 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 628 lazy->fetch(); 629 else if (s->isDefined()) 630 checkTableType(s, file, type); 631 return s; 632 } 633 634 TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) { 635 WasmLimits limits{0, 0, 0}; // Set by the writer. 636 WasmTableType *type = make<WasmTableType>(); 637 type->ElemType = uint8_t(ValType::FUNCREF); 638 type->Limits = limits; 639 StringRef module(defaultModule); 640 uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; 641 flags |= WASM_SYMBOL_UNDEFINED; 642 Symbol *sym = addUndefinedTable(name, name, module, flags, nullptr, type); 643 sym->markLive(); 644 sym->forceExport = config->exportTable; 645 return cast<TableSymbol>(sym); 646 } 647 648 TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) { 649 const uint32_t invalidIndex = -1; 650 WasmLimits limits{0, 0, 0}; // Set by the writer. 651 WasmTableType type{uint8_t(ValType::FUNCREF), limits}; 652 WasmTable desc{invalidIndex, type, name}; 653 InputTable *table = make<InputTable>(desc, nullptr); 654 uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; 655 TableSymbol *sym = addSyntheticTable(name, flags, table); 656 sym->markLive(); 657 sym->forceExport = config->exportTable; 658 return sym; 659 } 660 661 // Whether or not we need an indirect function table is usually a function of 662 // whether an input declares a need for it. However sometimes it's possible for 663 // no input to need the indirect function table, but then a late 664 // addInternalGOTEntry causes a function to be allocated an address. In that 665 // case address we synthesize a definition at the last minute. 666 TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) { 667 Symbol *existing = find(functionTableName); 668 if (existing) { 669 if (!isa<TableSymbol>(existing)) { 670 error(Twine("reserved symbol must be of type table: `") + 671 functionTableName + "`"); 672 return nullptr; 673 } 674 if (existing->isDefined()) { 675 error(Twine("reserved symbol must not be defined in input files: `") + 676 functionTableName + "`"); 677 return nullptr; 678 } 679 } 680 681 if (config->importTable) { 682 if (existing) 683 return cast<TableSymbol>(existing); 684 if (required) 685 return createUndefinedIndirectFunctionTable(functionTableName); 686 } else if ((existing && existing->isLive()) || config->exportTable || 687 required) { 688 // A defined table is required. Either because the user request an exported 689 // table or because the table symbol is already live. The existing table is 690 // guaranteed to be undefined due to the check above. 691 return createDefinedIndirectFunctionTable(functionTableName); 692 } 693 694 // An indirect function table will only be present in the symbol table if 695 // needed by a reloc; if we get here, we don't need one. 696 return nullptr; 697 } 698 699 void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) { 700 LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n"); 701 StringRef name = sym->getName(); 702 703 Symbol *s; 704 bool wasInserted; 705 std::tie(s, wasInserted) = insertName(name); 706 707 if (wasInserted) { 708 replaceSymbol<LazySymbol>(s, name, 0, file, *sym); 709 return; 710 } 711 712 if (!s->isUndefined()) 713 return; 714 715 // The existing symbol is undefined, load a new one from the archive, 716 // unless the existing symbol is weak in which case replace the undefined 717 // symbols with a LazySymbol. 718 if (s->isWeak()) { 719 const WasmSignature *oldSig = nullptr; 720 // In the case of an UndefinedFunction we need to preserve the expected 721 // signature. 722 if (auto *f = dyn_cast<UndefinedFunction>(s)) 723 oldSig = f->signature; 724 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 725 auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, 726 file, *sym); 727 newSym->signature = oldSig; 728 return; 729 } 730 731 LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 732 file->addMember(sym); 733 } 734 735 bool SymbolTable::addComdat(StringRef name) { 736 return comdatGroups.insert(CachedHashStringRef(name)).second; 737 } 738 739 // The new signature doesn't match. Create a variant to the symbol with the 740 // signature encoded in the name and return that instead. These symbols are 741 // then unified later in handleSymbolVariants. 742 bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, 743 const InputFile *file, Symbol **out) { 744 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " 745 << " " << toString(*sig) << "\n"); 746 Symbol *variant = nullptr; 747 748 // Linear search through symbol variants. Should never be more than two 749 // or three entries here. 750 auto &variants = symVariants[CachedHashStringRef(sym->getName())]; 751 if (variants.empty()) 752 variants.push_back(sym); 753 754 for (Symbol* v : variants) { 755 if (*v->getSignature() == *sig) { 756 variant = v; 757 break; 758 } 759 } 760 761 bool wasAdded = !variant; 762 if (wasAdded) { 763 // Create a new variant; 764 LLVM_DEBUG(dbgs() << "added new variant\n"); 765 variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 766 variant->isUsedInRegularObj = 767 !file || file->kind() == InputFile::ObjectKind; 768 variant->canInline = true; 769 variant->traced = false; 770 variant->forceExport = false; 771 variants.push_back(variant); 772 } else { 773 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); 774 assert(*variant->getSignature() == *sig); 775 } 776 777 *out = variant; 778 return wasAdded; 779 } 780 781 // Set a flag for --trace-symbol so that we can print out a log message 782 // if a new symbol with the same name is inserted into the symbol table. 783 void SymbolTable::trace(StringRef name) { 784 symMap.insert({CachedHashStringRef(name), -1}); 785 } 786 787 void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { 788 // Swap symbols as instructed by -wrap. 789 int &origIdx = symMap[CachedHashStringRef(sym->getName())]; 790 int &realIdx= symMap[CachedHashStringRef(real->getName())]; 791 int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; 792 LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); 793 794 // Anyone looking up __real symbols should get the original 795 realIdx = origIdx; 796 // Anyone looking up the original should get the __wrap symbol 797 origIdx = wrapIdx; 798 } 799 800 static const uint8_t unreachableFn[] = { 801 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 802 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 803 }; 804 805 // Replace the given symbol body with an unreachable function. 806 // This is used by handleWeakUndefines in order to generate a callable 807 // equivalent of an undefined function and also handleSymbolVariants for 808 // undefined functions that don't match the signature of the definition. 809 InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, 810 const WasmSignature &sig, 811 StringRef debugName) { 812 auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); 813 func->setBody(unreachableFn); 814 syntheticFunctions.emplace_back(func); 815 // Mark new symbols as local. For relocatable output we don't want them 816 // to be exported outside the object file. 817 replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL, 818 nullptr, func); 819 // Ensure the stub function doesn't get a table entry. Its address 820 // should always compare equal to the null pointer. 821 sym->isStub = true; 822 return func; 823 } 824 825 void SymbolTable::replaceWithUndefined(Symbol *sym) { 826 // Add a synthetic dummy for weak undefined functions. These dummies will 827 // be GC'd if not used as the target of any "call" instructions. 828 StringRef debugName = saver.save("undefined_weak:" + toString(*sym)); 829 replaceWithUnreachable(sym, *sym->getSignature(), debugName); 830 // Hide our dummy to prevent export. 831 sym->setHidden(true); 832 } 833 834 // For weak undefined functions, there may be "call" instructions that reference 835 // the symbol. In this case, we need to synthesise a dummy/stub function that 836 // will abort at runtime, so that relocations can still provided an operand to 837 // the call instruction that passes Wasm validation. 838 void SymbolTable::handleWeakUndefines() { 839 for (Symbol *sym : getSymbols()) { 840 if (sym->isUndefWeak()) { 841 if (sym->getSignature()) { 842 replaceWithUndefined(sym); 843 } else { 844 // It is possible for undefined functions not to have a signature (eg. 845 // if added via "--undefined"), but weak undefined ones do have a 846 // signature. Lazy symbols may not be functions and therefore Sig can 847 // still be null in some circumstance. 848 assert(!isa<FunctionSymbol>(sym)); 849 } 850 } 851 } 852 } 853 854 DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) { 855 if (stubFunctions.count(sig)) 856 return stubFunctions[sig]; 857 LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n"); 858 auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>()); 859 sym->isUsedInRegularObj = true; 860 sym->canInline = true; 861 sym->traced = false; 862 sym->forceExport = false; 863 sym->signature = &sig; 864 replaceSymbol<DefinedFunction>( 865 sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr); 866 replaceWithUnreachable(sym, sig, "undefined_stub"); 867 stubFunctions[sig] = sym; 868 return sym; 869 } 870 871 static void reportFunctionSignatureMismatch(StringRef symName, 872 FunctionSymbol *a, 873 FunctionSymbol *b, bool isError) { 874 std::string msg = ("function signature mismatch: " + symName + 875 "\n>>> defined as " + toString(*a->signature) + " in " + 876 toString(a->getFile()) + "\n>>> defined as " + 877 toString(*b->signature) + " in " + toString(b->getFile())) 878 .str(); 879 if (isError) 880 error(msg); 881 else 882 warn(msg); 883 } 884 885 // Remove any variant symbols that were created due to function signature 886 // mismatches. 887 void SymbolTable::handleSymbolVariants() { 888 for (auto pair : symVariants) { 889 // Push the initial symbol onto the list of variants. 890 StringRef symName = pair.first.val(); 891 std::vector<Symbol *> &variants = pair.second; 892 893 #ifndef NDEBUG 894 LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() 895 << ") variants: " << symName << "\n"); 896 for (auto *s: variants) { 897 auto *f = cast<FunctionSymbol>(s); 898 LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " 899 << toString(*f->signature) << "\n"); 900 } 901 #endif 902 903 // Find the one definition. 904 DefinedFunction *defined = nullptr; 905 for (auto *symbol : variants) { 906 if (auto f = dyn_cast<DefinedFunction>(symbol)) { 907 defined = f; 908 break; 909 } 910 } 911 912 // If there are no definitions, and the undefined symbols disagree on 913 // the signature, there is not we can do since we don't know which one 914 // to use as the signature on the import. 915 if (!defined) { 916 reportFunctionSignatureMismatch(symName, 917 cast<FunctionSymbol>(variants[0]), 918 cast<FunctionSymbol>(variants[1]), true); 919 return; 920 } 921 922 for (auto *symbol : variants) { 923 if (symbol != defined) { 924 auto *f = cast<FunctionSymbol>(symbol); 925 reportFunctionSignatureMismatch(symName, f, defined, false); 926 StringRef debugName = saver.save("signature_mismatch:" + toString(*f)); 927 replaceWithUnreachable(f, *f->signature, debugName); 928 } 929 } 930 } 931 } 932 933 } // namespace wasm 934 } // namespace lld 935