1 //===- SymbolTable.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SymbolTable.h" 10 #include "Config.h" 11 #include "InputChunks.h" 12 #include "InputEvent.h" 13 #include "InputGlobal.h" 14 #include "WriterUtils.h" 15 #include "lld/Common/ErrorHandler.h" 16 #include "lld/Common/Memory.h" 17 #include "llvm/ADT/SetVector.h" 18 19 #define DEBUG_TYPE "lld" 20 21 using namespace llvm; 22 using namespace llvm::wasm; 23 using namespace llvm::object; 24 using namespace lld; 25 using namespace lld::wasm; 26 27 SymbolTable *lld::wasm::Symtab; 28 29 void SymbolTable::addFile(InputFile *File) { 30 log("Processing: " + toString(File)); 31 if (Config->Trace) 32 message(toString(File)); 33 File->parse(); 34 35 // LLVM bitcode file 36 if (auto *F = dyn_cast<BitcodeFile>(File)) 37 BitcodeFiles.push_back(F); 38 else if (auto *F = dyn_cast<ObjFile>(File)) 39 ObjectFiles.push_back(F); 40 else if (auto *F = dyn_cast<SharedFile>(File)) 41 SharedFiles.push_back(F); 42 } 43 44 // This function is where all the optimizations of link-time 45 // optimization happens. When LTO is in use, some input files are 46 // not in native object file format but in the LLVM bitcode format. 47 // This function compiles bitcode files into a few big native files 48 // using LLVM functions and replaces bitcode symbols with the results. 49 // Because all bitcode files that the program consists of are passed 50 // to the compiler at once, it can do whole-program optimization. 51 void SymbolTable::addCombinedLTOObject() { 52 if (BitcodeFiles.empty()) 53 return; 54 55 // Compile bitcode files and replace bitcode symbols. 56 LTO.reset(new BitcodeCompiler); 57 for (BitcodeFile *F : BitcodeFiles) 58 LTO->add(*F); 59 60 for (StringRef Filename : LTO->compile()) { 61 auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"), ""); 62 Obj->parse(true); 63 ObjectFiles.push_back(Obj); 64 } 65 } 66 67 void SymbolTable::reportRemainingUndefines() { 68 for (const auto& Pair : SymMap) { 69 const Symbol *Sym = SymVector[Pair.second]; 70 if (!Sym->isUndefined() || Sym->isWeak()) 71 continue; 72 if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0) 73 continue; 74 if (!Sym->IsUsedInRegularObj) 75 continue; 76 error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym)); 77 } 78 } 79 80 Symbol *SymbolTable::find(StringRef Name) { 81 auto It = SymMap.find(CachedHashStringRef(Name)); 82 if (It == SymMap.end() || It->second == -1) 83 return nullptr; 84 return SymVector[It->second]; 85 } 86 87 void SymbolTable::replace(StringRef Name, Symbol* Sym) { 88 auto It = SymMap.find(CachedHashStringRef(Name)); 89 SymVector[It->second] = Sym; 90 } 91 92 std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) { 93 bool Trace = false; 94 auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); 95 int &SymIndex = P.first->second; 96 bool IsNew = P.second; 97 if (SymIndex == -1) { 98 SymIndex = SymVector.size(); 99 Trace = true; 100 IsNew = true; 101 } 102 103 if (!IsNew) 104 return {SymVector[SymIndex], false}; 105 106 Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 107 Sym->IsUsedInRegularObj = false; 108 Sym->CanInline = true; 109 Sym->Traced = Trace; 110 SymVector.emplace_back(Sym); 111 return {Sym, true}; 112 } 113 114 std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, 115 const InputFile *File) { 116 Symbol *S; 117 bool WasInserted; 118 std::tie(S, WasInserted) = insertName(Name); 119 120 if (!File || File->kind() == InputFile::ObjectKind) 121 S->IsUsedInRegularObj = true; 122 123 return {S, WasInserted}; 124 } 125 126 static void reportTypeError(const Symbol *Existing, const InputFile *File, 127 llvm::wasm::WasmSymbolType Type) { 128 error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " + 129 toString(Existing->getWasmType()) + " in " + 130 toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) + 131 " in " + toString(File)); 132 } 133 134 // Check the type of new symbol matches that of the symbol is replacing. 135 // Returns true if the function types match, false is there is a singature 136 // mismatch. 137 static bool signatureMatches(FunctionSymbol *Existing, 138 const WasmSignature *NewSig) { 139 if (!NewSig) 140 return true; 141 142 const WasmSignature *OldSig = Existing->Signature; 143 if (!OldSig) { 144 Existing->Signature = NewSig; 145 return true; 146 } 147 148 return *NewSig == *OldSig; 149 } 150 151 static void checkGlobalType(const Symbol *Existing, const InputFile *File, 152 const WasmGlobalType *NewType) { 153 if (!isa<GlobalSymbol>(Existing)) { 154 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL); 155 return; 156 } 157 158 const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType(); 159 if (*NewType != *OldType) { 160 error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " + 161 toString(*OldType) + " in " + toString(Existing->getFile()) + 162 "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); 163 } 164 } 165 166 static void checkEventType(const Symbol *Existing, const InputFile *File, 167 const WasmEventType *NewType, 168 const WasmSignature *NewSig) { 169 auto ExistingEvent = dyn_cast<EventSymbol>(Existing); 170 if (!isa<EventSymbol>(Existing)) { 171 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT); 172 return; 173 } 174 175 const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType(); 176 const WasmSignature *OldSig = ExistingEvent->Signature; 177 if (NewType->Attribute != OldType->Attribute) 178 error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " + 179 toString(*OldType) + " in " + toString(Existing->getFile()) + 180 "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); 181 if (*NewSig != *OldSig) 182 warn("Event signature mismatch: " + Existing->getName() + 183 "\n>>> defined as " + toString(*OldSig) + " in " + 184 toString(Existing->getFile()) + "\n>>> defined as " + 185 toString(*NewSig) + " in " + toString(File)); 186 } 187 188 static void checkDataType(const Symbol *Existing, const InputFile *File) { 189 if (!isa<DataSymbol>(Existing)) 190 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA); 191 } 192 193 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, 194 uint32_t Flags, 195 InputFunction *Function) { 196 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n"); 197 assert(!find(Name)); 198 SyntheticFunctions.emplace_back(Function); 199 return replaceSymbol<DefinedFunction>(insertName(Name).first, Name, 200 Flags, nullptr, Function); 201 } 202 203 DefinedData *SymbolTable::addOptionalDataSymbol(StringRef Name, uint32_t Value, 204 uint32_t Flags) { 205 Symbol *S = find(Name); 206 if (!S || S->isDefined()) 207 return nullptr; 208 LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << Name << "\n"); 209 auto *rtn = replaceSymbol<DefinedData>(S, Name, Flags); 210 rtn->setVirtualAddress(Value); 211 return rtn; 212 } 213 214 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name, 215 uint32_t Flags) { 216 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n"); 217 assert(!find(Name)); 218 return replaceSymbol<DefinedData>(insertName(Name).first, Name, Flags); 219 } 220 221 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, 222 InputGlobal *Global) { 223 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global 224 << "\n"); 225 assert(!find(Name)); 226 SyntheticGlobals.emplace_back(Global); 227 return replaceSymbol<DefinedGlobal>(insertName(Name).first, Name, Flags, 228 nullptr, Global); 229 } 230 231 static bool shouldReplace(const Symbol *Existing, InputFile *NewFile, 232 uint32_t NewFlags) { 233 // If existing symbol is undefined, replace it. 234 if (!Existing->isDefined()) { 235 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " 236 << Existing->getName() << "\n"); 237 return true; 238 } 239 240 // Now we have two defined symbols. If the new one is weak, we can ignore it. 241 if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { 242 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); 243 return false; 244 } 245 246 // If the existing symbol is weak, we should replace it. 247 if (Existing->isWeak()) { 248 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); 249 return true; 250 } 251 252 // Neither symbol is week. They conflict. 253 error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + 254 toString(Existing->getFile()) + "\n>>> defined in " + 255 toString(NewFile)); 256 return true; 257 } 258 259 Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags, 260 InputFile *File, 261 InputFunction *Function) { 262 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " [" 263 << (Function ? toString(Function->Signature) : "none") 264 << "]\n"); 265 Symbol *S; 266 bool WasInserted; 267 std::tie(S, WasInserted) = insert(Name, File); 268 269 auto Replace = [&](Symbol* Sym) { 270 // If the new defined function doesn't have signture (i.e. bitcode 271 // functions) but the old symbol does, then preserve the old signature 272 const WasmSignature *OldSig = S->getSignature(); 273 auto* NewSym = replaceSymbol<DefinedFunction>(Sym, Name, Flags, File, Function); 274 if (!NewSym->Signature) 275 NewSym->Signature = OldSig; 276 }; 277 278 if (WasInserted || S->isLazy()) { 279 Replace(S); 280 return S; 281 } 282 283 auto ExistingFunction = dyn_cast<FunctionSymbol>(S); 284 if (!ExistingFunction) { 285 reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION); 286 return S; 287 } 288 289 bool CheckSig = true; 290 if (auto UD = dyn_cast<UndefinedFunction>(ExistingFunction)) 291 CheckSig = UD->IsCalledDirectly; 292 293 if (CheckSig && Function && !signatureMatches(ExistingFunction, &Function->Signature)) { 294 Symbol* Variant; 295 if (getFunctionVariant(S, &Function->Signature, File, &Variant)) 296 // New variant, always replace 297 Replace(Variant); 298 else if (shouldReplace(S, File, Flags)) 299 // Variant already exists, replace it after checking shouldReplace 300 Replace(Variant); 301 302 // This variant we found take the place in the symbol table as the primary 303 // variant. 304 replace(Name, Variant); 305 return Variant; 306 } 307 308 // Existing function with matching signature. 309 if (shouldReplace(S, File, Flags)) 310 Replace(S); 311 312 return S; 313 } 314 315 Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags, 316 InputFile *File, InputSegment *Segment, 317 uint32_t Address, uint32_t Size) { 318 LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address 319 << "\n"); 320 Symbol *S; 321 bool WasInserted; 322 std::tie(S, WasInserted) = insert(Name, File); 323 324 auto Replace = [&]() { 325 replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); 326 }; 327 328 if (WasInserted || S->isLazy()) { 329 Replace(); 330 return S; 331 } 332 333 checkDataType(S, File); 334 335 if (shouldReplace(S, File, Flags)) 336 Replace(); 337 return S; 338 } 339 340 Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags, 341 InputFile *File, InputGlobal *Global) { 342 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n"); 343 344 Symbol *S; 345 bool WasInserted; 346 std::tie(S, WasInserted) = insert(Name, File); 347 348 auto Replace = [&]() { 349 replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); 350 }; 351 352 if (WasInserted || S->isLazy()) { 353 Replace(); 354 return S; 355 } 356 357 checkGlobalType(S, File, &Global->getType()); 358 359 if (shouldReplace(S, File, Flags)) 360 Replace(); 361 return S; 362 } 363 364 Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags, 365 InputFile *File, InputEvent *Event) { 366 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n"); 367 368 Symbol *S; 369 bool WasInserted; 370 std::tie(S, WasInserted) = insert(Name, File); 371 372 auto Replace = [&]() { 373 replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event); 374 }; 375 376 if (WasInserted || S->isLazy()) { 377 Replace(); 378 return S; 379 } 380 381 checkEventType(S, File, &Event->getType(), &Event->Signature); 382 383 if (shouldReplace(S, File, Flags)) 384 Replace(); 385 return S; 386 } 387 388 Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName, 389 StringRef ImportModule, 390 uint32_t Flags, InputFile *File, 391 const WasmSignature *Sig, 392 bool IsCalledDirectly) { 393 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << 394 " [" << (Sig ? toString(*Sig) : "none") << "]\n"); 395 396 Symbol *S; 397 bool WasInserted; 398 std::tie(S, WasInserted) = insert(Name, File); 399 if (S->Traced) 400 printTraceSymbolUndefined(Name, File); 401 402 auto Replace = [&]() { 403 replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags, 404 File, Sig, IsCalledDirectly); 405 }; 406 407 if (WasInserted) 408 Replace(); 409 else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 410 Lazy->fetch(); 411 else { 412 auto ExistingFunction = dyn_cast<FunctionSymbol>(S); 413 if (!ExistingFunction) { 414 reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION); 415 return S; 416 } 417 if (IsCalledDirectly && !signatureMatches(ExistingFunction, Sig)) 418 if (getFunctionVariant(S, Sig, File, &S)) 419 Replace(); 420 } 421 422 return S; 423 } 424 425 Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags, 426 InputFile *File) { 427 LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n"); 428 429 Symbol *S; 430 bool WasInserted; 431 std::tie(S, WasInserted) = insert(Name, File); 432 if (S->Traced) 433 printTraceSymbolUndefined(Name, File); 434 435 if (WasInserted) 436 replaceSymbol<UndefinedData>(S, Name, Flags, File); 437 else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 438 Lazy->fetch(); 439 else if (S->isDefined()) 440 checkDataType(S, File); 441 return S; 442 } 443 444 Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName, 445 StringRef ImportModule, uint32_t Flags, 446 InputFile *File, 447 const WasmGlobalType *Type) { 448 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n"); 449 450 Symbol *S; 451 bool WasInserted; 452 std::tie(S, WasInserted) = insert(Name, File); 453 if (S->Traced) 454 printTraceSymbolUndefined(Name, File); 455 456 if (WasInserted) 457 replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags, 458 File, Type); 459 else if (auto *Lazy = dyn_cast<LazySymbol>(S)) 460 Lazy->fetch(); 461 else if (S->isDefined()) 462 checkGlobalType(S, File, Type); 463 return S; 464 } 465 466 void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) { 467 LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); 468 StringRef Name = Sym->getName(); 469 470 Symbol *S; 471 bool WasInserted; 472 std::tie(S, WasInserted) = insertName(Name); 473 474 if (WasInserted) { 475 replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym); 476 return; 477 } 478 479 if (!S->isUndefined()) 480 return; 481 482 // The existing symbol is undefined, load a new one from the archive, 483 // unless the the existing symbol is weak in which case replace the undefined 484 // symbols with a LazySymbol. 485 if (S->isWeak()) { 486 const WasmSignature *OldSig = nullptr; 487 // In the case of an UndefinedFunction we need to preserve the expected 488 // signature. 489 if (auto *F = dyn_cast<UndefinedFunction>(S)) 490 OldSig = F->Signature; 491 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); 492 auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK, 493 File, *Sym); 494 NewSym->Signature = OldSig; 495 return; 496 } 497 498 LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); 499 File->addMember(Sym); 500 } 501 502 bool SymbolTable::addComdat(StringRef Name) { 503 return ComdatGroups.insert(CachedHashStringRef(Name)).second; 504 } 505 506 // The new signature doesn't match. Create a variant to the symbol with the 507 // signature encoded in the name and return that instead. These symbols are 508 // then unified later in handleSymbolVariants. 509 bool SymbolTable::getFunctionVariant(Symbol* Sym, const WasmSignature *Sig, 510 const InputFile *File, Symbol **Out) { 511 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << Sym->getName() << " -> " 512 << " " << toString(*Sig) << "\n"); 513 Symbol *Variant = nullptr; 514 515 // Linear search through symbol variants. Should never be more than two 516 // or three entries here. 517 auto &Variants = SymVariants[CachedHashStringRef(Sym->getName())]; 518 if (Variants.empty()) 519 Variants.push_back(Sym); 520 521 for (Symbol* V : Variants) { 522 if (*V->getSignature() == *Sig) { 523 Variant = V; 524 break; 525 } 526 } 527 528 bool WasAdded = !Variant; 529 if (WasAdded) { 530 // Create a new variant; 531 LLVM_DEBUG(dbgs() << "added new variant\n"); 532 Variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 533 Variants.push_back(Variant); 534 } else { 535 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*Variant) << "\n"); 536 assert(*Variant->getSignature() == *Sig); 537 } 538 539 *Out = Variant; 540 return WasAdded; 541 } 542 543 // Set a flag for --trace-symbol so that we can print out a log message 544 // if a new symbol with the same name is inserted into the symbol table. 545 void SymbolTable::trace(StringRef Name) { 546 SymMap.insert({CachedHashStringRef(Name), -1}); 547 } 548 549 void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) { 550 // Swap symbols as instructed by -wrap. 551 int &OrigIdx = SymMap[CachedHashStringRef(Sym->getName())]; 552 int &RealIdx= SymMap[CachedHashStringRef(Real->getName())]; 553 int &WrapIdx = SymMap[CachedHashStringRef(Wrap->getName())]; 554 LLVM_DEBUG(dbgs() << "wrap: " << Sym->getName() << "\n"); 555 556 // Anyone looking up __real symbols should get the original 557 RealIdx = OrigIdx; 558 // Anyone looking up the original should get the __wrap symbol 559 OrigIdx = WrapIdx; 560 } 561 562 static const uint8_t UnreachableFn[] = { 563 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, 564 0x00 /* opcode unreachable */, 0x0b /* opcode end */ 565 }; 566 567 // Replace the given symbol body with an unreachable function. 568 // This is used by handleWeakUndefines in order to generate a callable 569 // equivalent of an undefined function and also handleSymbolVariants for 570 // undefined functions that don't match the signature of the definition. 571 InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym, 572 const WasmSignature &Sig, 573 StringRef DebugName) { 574 auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName); 575 Func->setBody(UnreachableFn); 576 SyntheticFunctions.emplace_back(Func); 577 replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr, 578 Func); 579 return Func; 580 } 581 582 // For weak undefined functions, there may be "call" instructions that reference 583 // the symbol. In this case, we need to synthesise a dummy/stub function that 584 // will abort at runtime, so that relocations can still provided an operand to 585 // the call instruction that passes Wasm validation. 586 void SymbolTable::handleWeakUndefines() { 587 for (Symbol *Sym : getSymbols()) { 588 if (!Sym->isUndefWeak()) 589 continue; 590 591 const WasmSignature *Sig = Sym->getSignature(); 592 if (!Sig) { 593 // It is possible for undefined functions not to have a signature (eg. if 594 // added via "--undefined"), but weak undefined ones do have a signature. 595 // Lazy symbols may not be functions and therefore Sig can still be null 596 // in some circumstantce. 597 assert(!isa<FunctionSymbol>(Sym)); 598 continue; 599 } 600 601 // Add a synthetic dummy for weak undefined functions. These dummies will 602 // be GC'd if not used as the target of any "call" instructions. 603 StringRef DebugName = Saver.save("undefined:" + toString(*Sym)); 604 InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName); 605 // Ensure it compares equal to the null pointer, and so that table relocs 606 // don't pull in the stub body (only call-operand relocs should do that). 607 Func->setTableIndex(0); 608 // Hide our dummy to prevent export. 609 Sym->setHidden(true); 610 } 611 } 612 613 static void reportFunctionSignatureMismatch(StringRef SymName, 614 FunctionSymbol *A, 615 FunctionSymbol *B, bool Error) { 616 std::string msg = ("function signature mismatch: " + SymName + 617 "\n>>> defined as " + toString(*A->Signature) + " in " + 618 toString(A->getFile()) + "\n>>> defined as " + 619 toString(*B->Signature) + " in " + toString(B->getFile())) 620 .str(); 621 if (Error) 622 error(msg); 623 else 624 warn(msg); 625 } 626 627 // Remove any variant symbols that were created due to function signature 628 // mismatches. 629 void SymbolTable::handleSymbolVariants() { 630 for (auto Pair : SymVariants) { 631 // Push the initial symbol onto the list of variants. 632 StringRef SymName = Pair.first.val(); 633 std::vector<Symbol *> &Variants = Pair.second; 634 635 #ifndef NDEBUG 636 LLVM_DEBUG(dbgs() << "symbol with (" << Variants.size() 637 << ") variants: " << SymName << "\n"); 638 for (auto *S: Variants) { 639 auto *F = cast<FunctionSymbol>(S); 640 LLVM_DEBUG(dbgs() << " variant: " + F->getName() << " " 641 << toString(*F->Signature) << "\n"); 642 } 643 #endif 644 645 // Find the one definition. 646 DefinedFunction *Defined = nullptr; 647 for (auto *Symbol : Variants) { 648 if (auto F = dyn_cast<DefinedFunction>(Symbol)) { 649 Defined = F; 650 break; 651 } 652 } 653 654 // If there are no definitions, and the undefined symbols disagree on 655 // the signature, there is not we can do since we don't know which one 656 // to use as the signature on the import. 657 if (!Defined) { 658 reportFunctionSignatureMismatch(SymName, 659 cast<FunctionSymbol>(Variants[0]), 660 cast<FunctionSymbol>(Variants[1]), true); 661 return; 662 } 663 664 for (auto *Symbol : Variants) { 665 if (Symbol != Defined) { 666 auto *F = cast<FunctionSymbol>(Symbol); 667 reportFunctionSignatureMismatch(SymName, F, Defined, false); 668 StringRef DebugName = Saver.save("unreachable:" + toString(*F)); 669 replaceWithUnreachable(F, *F->Signature, DebugName); 670 } 671 } 672 } 673 } 674