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