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::compileBitcodeFiles() { 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 happens 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 WasmSignature *newSig) { 173 const auto *existingTag = dyn_cast<TagSymbol>(existing); 174 if (!isa<TagSymbol>(existing)) { 175 reportTypeError(existing, file, WASM_SYMBOL_TYPE_TAG); 176 return; 177 } 178 179 const WasmSignature *oldSig = existingTag->signature; 180 if (*newSig != *oldSig) 181 warn("Tag signature mismatch: " + existing->getName() + 182 "\n>>> defined as " + toString(*oldSig) + " in " + 183 toString(existing->getFile()) + "\n>>> defined as " + 184 toString(*newSig) + " in " + toString(file)); 185 } 186 187 static void checkTableType(const Symbol *existing, const InputFile *file, 188 const WasmTableType *newType) { 189 if (!isa<TableSymbol>(existing)) { 190 reportTypeError(existing, file, WASM_SYMBOL_TYPE_TABLE); 191 return; 192 } 193 194 const WasmTableType *oldType = cast<TableSymbol>(existing)->getTableType(); 195 if (newType->ElemType != oldType->ElemType) { 196 error("Table type mismatch: " + existing->getName() + "\n>>> defined as " + 197 toString(*oldType) + " in " + toString(existing->getFile()) + 198 "\n>>> defined as " + toString(*newType) + " in " + toString(file)); 199 } 200 // FIXME: No assertions currently on the limits. 201 } 202 203 static void checkDataType(const Symbol *existing, const InputFile *file) { 204 if (!isa<DataSymbol>(existing)) 205 reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA); 206 } 207 208 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, 209 uint32_t flags, 210 InputFunction *function) { 211 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); 212 assert(!find(name)); 213 syntheticFunctions.emplace_back(function); 214 return replaceSymbol<DefinedFunction>(insertName(name).first, name, 215 flags, nullptr, function); 216 } 217 218 // Adds an optional, linker generated, data symbol. The symbol will only be 219 // added if there is an undefine reference to it, or if it is explicitly 220 // exported via the --export flag. Otherwise we don't add the symbol and return 221 // nullptr. 222 DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, 223 uint64_t value) { 224 Symbol *s = find(name); 225 if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0)) 226 s = insertName(name).first; 227 else if (!s || s->isDefined()) 228 return nullptr; 229 LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n"); 230 auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN); 231 rtn->setVA(value); 232 rtn->referenced = true; 233 return rtn; 234 } 235 236 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, 237 uint32_t flags) { 238 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); 239 assert(!find(name)); 240 return replaceSymbol<DefinedData>(insertName(name).first, name, flags); 241 } 242 243 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, 244 InputGlobal *global) { 245 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global 246 << "\n"); 247 assert(!find(name)); 248 syntheticGlobals.emplace_back(global); 249 return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags, 250 nullptr, global); 251 } 252 253 DefinedGlobal *SymbolTable::addOptionalGlobalSymbol(StringRef name, 254 InputGlobal *global) { 255 Symbol *s = find(name); 256 if (!s || s->isDefined()) 257 return nullptr; 258 LLVM_DEBUG(dbgs() << "addOptionalGlobalSymbol: " << name << " -> " << global 259 << "\n"); 260 syntheticGlobals.emplace_back(global); 261 return replaceSymbol<DefinedGlobal>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN, 262 nullptr, global); 263 } 264 265 DefinedTable *SymbolTable::addSyntheticTable(StringRef name, uint32_t flags, 266 InputTable *table) { 267 LLVM_DEBUG(dbgs() << "addSyntheticTable: " << name << " -> " << table 268 << "\n"); 269 Symbol *s = find(name); 270 assert(!s || s->isUndefined()); 271 if (!s) 272 s = insertName(name).first; 273 syntheticTables.emplace_back(table); 274 return replaceSymbol<DefinedTable>(s, name, flags, nullptr, table); 275 } 276 277 static bool shouldReplace(const Symbol *existing, InputFile *newFile, 278 uint32_t newFlags) { 279 // If existing symbol is undefined, replace it. 280 if (!existing->isDefined()) { 281 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 282 << existing->getName() << "\n"); 283 return true; 284 } 285 286 // Now we have two defined symbols. If the new one is weak, we can ignore it. 287 if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 288 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 289 return false; 290 } 291 292 // If the existing symbol is weak, we should replace it. 293 if (existing->isWeak()) { 294 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 295 return true; 296 } 297 298 // Neither symbol is week. They conflict. 299 error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + 300 toString(existing->getFile()) + "\n>>> defined in " + 301 toString(newFile)); 302 return true; 303 } 304 305 Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags, 306 InputFile *file, 307 InputFunction *function) { 308 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " [" 309 << (function ? toString(function->signature) : "none") 310 << "]\n"); 311 Symbol *s; 312 bool wasInserted; 313 std::tie(s, wasInserted) = insert(name, file); 314 315 auto replaceSym = [&](Symbol *sym) { 316 // If the new defined function doesn't have signature (i.e. bitcode 317 // functions) but the old symbol does, then preserve the old signature 318 const WasmSignature *oldSig = s->getSignature(); 319 auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function); 320 if (!newSym->signature) 321 newSym->signature = oldSig; 322 }; 323 324 if (wasInserted || s->isLazy()) { 325 replaceSym(s); 326 return s; 327 } 328 329 auto existingFunction = dyn_cast<FunctionSymbol>(s); 330 if (!existingFunction) { 331 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 332 return s; 333 } 334 335 bool checkSig = true; 336 if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) 337 checkSig = ud->isCalledDirectly; 338 339 if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) { 340 Symbol* variant; 341 if (getFunctionVariant(s, &function->signature, file, &variant)) 342 // New variant, always replace 343 replaceSym(variant); 344 else if (shouldReplace(s, file, flags)) 345 // Variant already exists, replace it after checking shouldReplace 346 replaceSym(variant); 347 348 // This variant we found take the place in the symbol table as the primary 349 // variant. 350 replace(name, variant); 351 return variant; 352 } 353 354 // Existing function with matching signature. 355 if (shouldReplace(s, file, flags)) 356 replaceSym(s); 357 358 return s; 359 } 360 361 Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, 362 InputFile *file, InputChunk *segment, 363 uint64_t address, uint64_t size) { 364 LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address 365 << "\n"); 366 Symbol *s; 367 bool wasInserted; 368 std::tie(s, wasInserted) = insert(name, file); 369 370 auto replaceSym = [&]() { 371 replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size); 372 }; 373 374 if (wasInserted || s->isLazy()) { 375 replaceSym(); 376 return s; 377 } 378 379 checkDataType(s, file); 380 381 if (shouldReplace(s, file, flags)) 382 replaceSym(); 383 return s; 384 } 385 386 Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags, 387 InputFile *file, InputGlobal *global) { 388 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n"); 389 390 Symbol *s; 391 bool wasInserted; 392 std::tie(s, wasInserted) = insert(name, file); 393 394 auto replaceSym = [&]() { 395 replaceSymbol<DefinedGlobal>(s, name, flags, file, global); 396 }; 397 398 if (wasInserted || s->isLazy()) { 399 replaceSym(); 400 return s; 401 } 402 403 checkGlobalType(s, file, &global->getType()); 404 405 if (shouldReplace(s, file, flags)) 406 replaceSym(); 407 return s; 408 } 409 410 Symbol *SymbolTable::addDefinedTag(StringRef name, uint32_t flags, 411 InputFile *file, InputTag *tag) { 412 LLVM_DEBUG(dbgs() << "addDefinedTag:" << name << "\n"); 413 414 Symbol *s; 415 bool wasInserted; 416 std::tie(s, wasInserted) = insert(name, file); 417 418 auto replaceSym = [&]() { 419 replaceSymbol<DefinedTag>(s, name, flags, file, tag); 420 }; 421 422 if (wasInserted || s->isLazy()) { 423 replaceSym(); 424 return s; 425 } 426 427 checkTagType(s, file, &tag->signature); 428 429 if (shouldReplace(s, file, flags)) 430 replaceSym(); 431 return s; 432 } 433 434 Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags, 435 InputFile *file, InputTable *table) { 436 LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n"); 437 438 Symbol *s; 439 bool wasInserted; 440 std::tie(s, wasInserted) = insert(name, file); 441 442 auto replaceSym = [&]() { 443 replaceSymbol<DefinedTable>(s, name, flags, file, table); 444 }; 445 446 if (wasInserted || s->isLazy()) { 447 replaceSym(); 448 return s; 449 } 450 451 checkTableType(s, file, &table->getType()); 452 453 if (shouldReplace(s, file, flags)) 454 replaceSym(); 455 return s; 456 } 457 458 // This function get called when an undefined symbol is added, and there is 459 // already an existing one in the symbols table. In this case we check that 460 // custom 'import-module' and 'import-field' symbol attributes agree. 461 // With LTO these attributes are not available when the bitcode is read and only 462 // become available when the LTO object is read. In this case we silently 463 // replace the empty attributes with the valid ones. 464 template <typename T> 465 static void setImportAttributes(T *existing, Optional<StringRef> importName, 466 Optional<StringRef> importModule, 467 uint32_t flags, InputFile *file) { 468 if (importName) { 469 if (!existing->importName) 470 existing->importName = importName; 471 if (existing->importName != importName) 472 error("import name mismatch for symbol: " + toString(*existing) + 473 "\n>>> defined as " + *existing->importName + " in " + 474 toString(existing->getFile()) + "\n>>> defined as " + *importName + 475 " in " + toString(file)); 476 } 477 478 if (importModule) { 479 if (!existing->importModule) 480 existing->importModule = importModule; 481 if (existing->importModule != importModule) 482 error("import module mismatch for symbol: " + toString(*existing) + 483 "\n>>> defined as " + *existing->importModule + " in " + 484 toString(existing->getFile()) + "\n>>> defined as " + 485 *importModule + " in " + toString(file)); 486 } 487 488 // Update symbol binding, if the existing symbol is weak 489 uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK; 490 if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) { 491 existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding; 492 } 493 } 494 495 Symbol *SymbolTable::addUndefinedFunction(StringRef name, 496 Optional<StringRef> importName, 497 Optional<StringRef> importModule, 498 uint32_t flags, InputFile *file, 499 const WasmSignature *sig, 500 bool isCalledDirectly) { 501 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" 502 << (sig ? toString(*sig) : "none") 503 << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x" 504 << utohexstr(flags) << "\n"); 505 assert(flags & WASM_SYMBOL_UNDEFINED); 506 507 Symbol *s; 508 bool wasInserted; 509 std::tie(s, wasInserted) = insert(name, file); 510 if (s->traced) 511 printTraceSymbolUndefined(name, file); 512 513 auto replaceSym = [&]() { 514 replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags, 515 file, sig, isCalledDirectly); 516 }; 517 518 if (wasInserted) { 519 replaceSym(); 520 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 521 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 522 lazy->setWeak(); 523 lazy->signature = sig; 524 } else { 525 lazy->fetch(); 526 } 527 } else { 528 auto existingFunction = dyn_cast<FunctionSymbol>(s); 529 if (!existingFunction) { 530 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); 531 return s; 532 } 533 if (!existingFunction->signature && sig) 534 existingFunction->signature = sig; 535 auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction); 536 if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { 537 // If the existing undefined functions is not called directly then let 538 // this one take precedence. Otherwise the existing function is either 539 // directly called or defined, in which case we need a function variant. 540 if (existingUndefined && !existingUndefined->isCalledDirectly) 541 replaceSym(); 542 else if (getFunctionVariant(s, sig, file, &s)) 543 replaceSym(); 544 } 545 if (existingUndefined) { 546 setImportAttributes(existingUndefined, importName, importModule, flags, 547 file); 548 if (isCalledDirectly) 549 existingUndefined->isCalledDirectly = true; 550 } 551 } 552 553 return s; 554 } 555 556 Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, 557 InputFile *file) { 558 LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); 559 assert(flags & WASM_SYMBOL_UNDEFINED); 560 561 Symbol *s; 562 bool wasInserted; 563 std::tie(s, wasInserted) = insert(name, file); 564 if (s->traced) 565 printTraceSymbolUndefined(name, file); 566 567 if (wasInserted) { 568 replaceSymbol<UndefinedData>(s, name, flags, file); 569 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) { 570 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) 571 lazy->setWeak(); 572 else 573 lazy->fetch(); 574 } else if (s->isDefined()) { 575 checkDataType(s, file); 576 } 577 return s; 578 } 579 580 Symbol *SymbolTable::addUndefinedGlobal(StringRef name, 581 Optional<StringRef> importName, 582 Optional<StringRef> importModule, 583 uint32_t flags, InputFile *file, 584 const WasmGlobalType *type) { 585 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); 586 assert(flags & WASM_SYMBOL_UNDEFINED); 587 588 Symbol *s; 589 bool wasInserted; 590 std::tie(s, wasInserted) = insert(name, file); 591 if (s->traced) 592 printTraceSymbolUndefined(name, file); 593 594 if (wasInserted) 595 replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, 596 file, type); 597 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 598 lazy->fetch(); 599 else if (s->isDefined()) 600 checkGlobalType(s, file, type); 601 return s; 602 } 603 604 Symbol *SymbolTable::addUndefinedTable(StringRef name, 605 Optional<StringRef> importName, 606 Optional<StringRef> importModule, 607 uint32_t flags, InputFile *file, 608 const WasmTableType *type) { 609 LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n"); 610 assert(flags & WASM_SYMBOL_UNDEFINED); 611 612 Symbol *s; 613 bool wasInserted; 614 std::tie(s, wasInserted) = insert(name, file); 615 if (s->traced) 616 printTraceSymbolUndefined(name, file); 617 618 if (wasInserted) 619 replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags, 620 file, type); 621 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 622 lazy->fetch(); 623 else if (s->isDefined()) 624 checkTableType(s, file, type); 625 return s; 626 } 627 628 Symbol *SymbolTable::addUndefinedTag(StringRef name, 629 Optional<StringRef> importName, 630 Optional<StringRef> importModule, 631 uint32_t flags, InputFile *file, 632 const WasmSignature *sig) { 633 LLVM_DEBUG(dbgs() << "addUndefinedTag: " << name << "\n"); 634 assert(flags & WASM_SYMBOL_UNDEFINED); 635 636 Symbol *s; 637 bool wasInserted; 638 std::tie(s, wasInserted) = insert(name, file); 639 if (s->traced) 640 printTraceSymbolUndefined(name, file); 641 642 if (wasInserted) 643 replaceSymbol<UndefinedTag>(s, name, importName, importModule, flags, file, 644 sig); 645 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 646 lazy->fetch(); 647 else if (s->isDefined()) 648 checkTagType(s, file, sig); 649 return s; 650 } 651 652 TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) { 653 WasmLimits limits{0, 0, 0}; // Set by the writer. 654 WasmTableType *type = make<WasmTableType>(); 655 type->ElemType = uint8_t(ValType::FUNCREF); 656 type->Limits = limits; 657 StringRef module(defaultModule); 658 uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; 659 flags |= WASM_SYMBOL_UNDEFINED; 660 Symbol *sym = addUndefinedTable(name, name, module, flags, nullptr, type); 661 sym->markLive(); 662 sym->forceExport = config->exportTable; 663 return cast<TableSymbol>(sym); 664 } 665 666 TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) { 667 const uint32_t invalidIndex = -1; 668 WasmLimits limits{0, 0, 0}; // Set by the writer. 669 WasmTableType type{uint8_t(ValType::FUNCREF), limits}; 670 WasmTable desc{invalidIndex, type, name}; 671 InputTable *table = make<InputTable>(desc, nullptr); 672 uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; 673 TableSymbol *sym = addSyntheticTable(name, flags, table); 674 sym->markLive(); 675 sym->forceExport = config->exportTable; 676 return sym; 677 } 678 679 // Whether or not we need an indirect function table is usually a function of 680 // whether an input declares a need for it. However sometimes it's possible for 681 // no input to need the indirect function table, but then a late 682 // addInternalGOTEntry causes a function to be allocated an address. In that 683 // case address we synthesize a definition at the last minute. 684 TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) { 685 Symbol *existing = find(functionTableName); 686 if (existing) { 687 if (!isa<TableSymbol>(existing)) { 688 error(Twine("reserved symbol must be of type table: `") + 689 functionTableName + "`"); 690 return nullptr; 691 } 692 if (existing->isDefined()) { 693 error(Twine("reserved symbol must not be defined in input files: `") + 694 functionTableName + "`"); 695 return nullptr; 696 } 697 } 698 699 if (config->importTable) { 700 if (existing) 701 return cast<TableSymbol>(existing); 702 if (required) 703 return createUndefinedIndirectFunctionTable(functionTableName); 704 } else if ((existing && existing->isLive()) || config->exportTable || 705 required) { 706 // A defined table is required. Either because the user request an exported 707 // table or because the table symbol is already live. The existing table is 708 // guaranteed to be undefined due to the check above. 709 return createDefinedIndirectFunctionTable(functionTableName); 710 } 711 712 // An indirect function table will only be present in the symbol table if 713 // needed by a reloc; if we get here, we don't need one. 714 return nullptr; 715 } 716 717 void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) { 718 LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n"); 719 StringRef name = sym->getName(); 720 721 Symbol *s; 722 bool wasInserted; 723 std::tie(s, wasInserted) = insertName(name); 724 725 if (wasInserted) { 726 replaceSymbol<LazySymbol>(s, name, 0, file, *sym); 727 return; 728 } 729 730 if (!s->isUndefined()) 731 return; 732 733 // The existing symbol is undefined, load a new one from the archive, 734 // unless the existing symbol is weak in which case replace the undefined 735 // symbols with a LazySymbol. 736 if (s->isWeak()) { 737 const WasmSignature *oldSig = nullptr; 738 // In the case of an UndefinedFunction we need to preserve the expected 739 // signature. 740 if (auto *f = dyn_cast<UndefinedFunction>(s)) 741 oldSig = f->signature; 742 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 743 auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, 744 file, *sym); 745 newSym->signature = oldSig; 746 return; 747 } 748 749 LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 750 file->addMember(sym); 751 } 752 753 bool SymbolTable::addComdat(StringRef name) { 754 return comdatGroups.insert(CachedHashStringRef(name)).second; 755 } 756 757 // The new signature doesn't match. Create a variant to the symbol with the 758 // signature encoded in the name and return that instead. These symbols are 759 // then unified later in handleSymbolVariants. 760 bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, 761 const InputFile *file, Symbol **out) { 762 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " 763 << " " << toString(*sig) << "\n"); 764 Symbol *variant = nullptr; 765 766 // Linear search through symbol variants. Should never be more than two 767 // or three entries here. 768 auto &variants = symVariants[CachedHashStringRef(sym->getName())]; 769 if (variants.empty()) 770 variants.push_back(sym); 771 772 for (Symbol* v : variants) { 773 if (*v->getSignature() == *sig) { 774 variant = v; 775 break; 776 } 777 } 778 779 bool wasAdded = !variant; 780 if (wasAdded) { 781 // Create a new variant; 782 LLVM_DEBUG(dbgs() << "added new variant\n"); 783 variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 784 variant->isUsedInRegularObj = 785 !file || file->kind() == InputFile::ObjectKind; 786 variant->canInline = true; 787 variant->traced = false; 788 variant->forceExport = false; 789 variants.push_back(variant); 790 } else { 791 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); 792 assert(*variant->getSignature() == *sig); 793 } 794 795 *out = variant; 796 return wasAdded; 797 } 798 799 // Set a flag for --trace-symbol so that we can print out a log message 800 // if a new symbol with the same name is inserted into the symbol table. 801 void SymbolTable::trace(StringRef name) { 802 symMap.insert({CachedHashStringRef(name), -1}); 803 } 804 805 void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { 806 // Swap symbols as instructed by -wrap. 807 int &origIdx = symMap[CachedHashStringRef(sym->getName())]; 808 int &realIdx= symMap[CachedHashStringRef(real->getName())]; 809 int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; 810 LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); 811 812 // Anyone looking up __real symbols should get the original 813 realIdx = origIdx; 814 // Anyone looking up the original should get the __wrap symbol 815 origIdx = wrapIdx; 816 } 817 818 static const uint8_t unreachableFn[] = { 819 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 820 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 821 }; 822 823 // Replace the given symbol body with an unreachable function. 824 // This is used by handleWeakUndefines in order to generate a callable 825 // equivalent of an undefined function and also handleSymbolVariants for 826 // undefined functions that don't match the signature of the definition. 827 InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, 828 const WasmSignature &sig, 829 StringRef debugName) { 830 auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); 831 func->setBody(unreachableFn); 832 syntheticFunctions.emplace_back(func); 833 // Mark new symbols as local. For relocatable output we don't want them 834 // to be exported outside the object file. 835 replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL, 836 nullptr, func); 837 // Ensure the stub function doesn't get a table entry. Its address 838 // should always compare equal to the null pointer. 839 sym->isStub = true; 840 return func; 841 } 842 843 void SymbolTable::replaceWithUndefined(Symbol *sym) { 844 // Add a synthetic dummy for weak undefined functions. These dummies will 845 // be GC'd if not used as the target of any "call" instructions. 846 StringRef debugName = saver.save("undefined_weak:" + toString(*sym)); 847 replaceWithUnreachable(sym, *sym->getSignature(), debugName); 848 // Hide our dummy to prevent export. 849 sym->setHidden(true); 850 } 851 852 // For weak undefined functions, there may be "call" instructions that reference 853 // the symbol. In this case, we need to synthesise a dummy/stub function that 854 // will abort at runtime, so that relocations can still provided an operand to 855 // the call instruction that passes Wasm validation. 856 void SymbolTable::handleWeakUndefines() { 857 for (Symbol *sym : getSymbols()) { 858 if (sym->isUndefWeak()) { 859 if (sym->getSignature()) { 860 replaceWithUndefined(sym); 861 } else { 862 // It is possible for undefined functions not to have a signature (eg. 863 // if added via "--undefined"), but weak undefined ones do have a 864 // signature. Lazy symbols may not be functions and therefore Sig can 865 // still be null in some circumstance. 866 assert(!isa<FunctionSymbol>(sym)); 867 } 868 } 869 } 870 } 871 872 DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) { 873 if (stubFunctions.count(sig)) 874 return stubFunctions[sig]; 875 LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n"); 876 auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>()); 877 sym->isUsedInRegularObj = true; 878 sym->canInline = true; 879 sym->traced = false; 880 sym->forceExport = false; 881 sym->signature = &sig; 882 replaceSymbol<DefinedFunction>( 883 sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr); 884 replaceWithUnreachable(sym, sig, "undefined_stub"); 885 stubFunctions[sig] = sym; 886 return sym; 887 } 888 889 static void reportFunctionSignatureMismatch(StringRef symName, 890 FunctionSymbol *a, 891 FunctionSymbol *b, bool isError) { 892 std::string msg = ("function signature mismatch: " + symName + 893 "\n>>> defined as " + toString(*a->signature) + " in " + 894 toString(a->getFile()) + "\n>>> defined as " + 895 toString(*b->signature) + " in " + toString(b->getFile())) 896 .str(); 897 if (isError) 898 error(msg); 899 else 900 warn(msg); 901 } 902 903 // Remove any variant symbols that were created due to function signature 904 // mismatches. 905 void SymbolTable::handleSymbolVariants() { 906 for (auto pair : symVariants) { 907 // Push the initial symbol onto the list of variants. 908 StringRef symName = pair.first.val(); 909 std::vector<Symbol *> &variants = pair.second; 910 911 #ifndef NDEBUG 912 LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() 913 << ") variants: " << symName << "\n"); 914 for (auto *s: variants) { 915 auto *f = cast<FunctionSymbol>(s); 916 LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " 917 << toString(*f->signature) << "\n"); 918 } 919 #endif 920 921 // Find the one definition. 922 DefinedFunction *defined = nullptr; 923 for (auto *symbol : variants) { 924 if (auto f = dyn_cast<DefinedFunction>(symbol)) { 925 defined = f; 926 break; 927 } 928 } 929 930 // If there are no definitions, and the undefined symbols disagree on 931 // the signature, there is not we can do since we don't know which one 932 // to use as the signature on the import. 933 if (!defined) { 934 reportFunctionSignatureMismatch(symName, 935 cast<FunctionSymbol>(variants[0]), 936 cast<FunctionSymbol>(variants[1]), true); 937 return; 938 } 939 940 for (auto *symbol : variants) { 941 if (symbol != defined) { 942 auto *f = cast<FunctionSymbol>(symbol); 943 reportFunctionSignatureMismatch(symName, f, defined, false); 944 StringRef debugName = saver.save("signature_mismatch:" + toString(*f)); 945 replaceWithUnreachable(f, *f->signature, debugName); 946 } 947 } 948 } 949 } 950 951 } // namespace wasm 952 } // namespace lld 953