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