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 "ConcatOutputSection.h" 11 #include "Config.h" 12 #include "InputFiles.h" 13 #include "InputSection.h" 14 #include "Symbols.h" 15 #include "SyntheticSections.h" 16 #include "lld/Common/ErrorHandler.h" 17 #include "lld/Common/Memory.h" 18 #include "llvm/Demangle/Demangle.h" 19 20 using namespace llvm; 21 using namespace lld; 22 using namespace lld::macho; 23 24 Symbol *SymbolTable::find(CachedHashStringRef cachedName) { 25 auto it = symMap.find(cachedName); 26 if (it == symMap.end()) 27 return nullptr; 28 return symVector[it->second]; 29 } 30 31 std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, 32 const InputFile *file) { 33 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 34 35 Symbol *sym; 36 if (!p.second) { 37 // Name already present in the symbol table. 38 sym = symVector[p.first->second]; 39 } else { 40 // Name is a new symbol. 41 sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 42 symVector.push_back(sym); 43 } 44 45 sym->isUsedInRegularObj |= !file || isa<ObjFile>(file); 46 return {sym, p.second}; 47 } 48 49 namespace { 50 struct DuplicateSymbolDiag { 51 // Pair containing source location and source file 52 const std::pair<std::string, std::string> src1; 53 const std::pair<std::string, std::string> src2; 54 const Symbol *sym; 55 56 DuplicateSymbolDiag(const std::pair<std::string, std::string> src1, 57 const std::pair<std::string, std::string> src2, 58 const Symbol *sym) 59 : src1(src1), src2(src2), sym(sym) {} 60 }; 61 SmallVector<DuplicateSymbolDiag> dupSymDiags; 62 } // namespace 63 64 // Move symbols at \p fromOff in \p fromIsec into \p toIsec, unless that symbol 65 // is \p skip. 66 static void transplantSymbolsAtOffset(InputSection *fromIsec, 67 InputSection *toIsec, Defined *skip, 68 uint64_t fromOff, uint64_t toOff) { 69 // Ensure the symbols will still be in address order after our insertions. 70 auto insertIt = llvm::upper_bound(toIsec->symbols, toOff, 71 [](uint64_t off, const Symbol *s) { 72 return cast<Defined>(s)->value < off; 73 }); 74 llvm::erase_if(fromIsec->symbols, [&](Symbol *s) { 75 auto *d = cast<Defined>(s); 76 if (d->value != fromOff) 77 return false; 78 if (d != skip) { 79 // This repeated insertion will be quadratic unless insertIt is the end 80 // iterator. However, that is typically the case for files that have 81 // .subsections_via_symbols set. 82 insertIt = toIsec->symbols.insert(insertIt, d); 83 d->isec = toIsec; 84 d->value = toOff; 85 // We don't want to have more than one unwindEntry at a given address, so 86 // drop the redundant ones. We We can safely drop the unwindEntries of 87 // the symbols in fromIsec since we will be adding another unwindEntry as 88 // we finish parsing toIsec's file. (We can assume that toIsec has its 89 // own unwindEntry because of the ODR.) 90 d->unwindEntry = nullptr; 91 } 92 return true; 93 }); 94 } 95 96 Defined *SymbolTable::addDefined(StringRef name, InputFile *file, 97 InputSection *isec, uint64_t value, 98 uint64_t size, bool isWeakDef, 99 bool isPrivateExtern, 100 bool isReferencedDynamically, bool noDeadStrip, 101 bool isWeakDefCanBeHidden) { 102 bool overridesWeakDef = false; 103 auto [s, wasInserted] = insert(name, file); 104 105 assert(!file || !isa<BitcodeFile>(file) || !isec); 106 107 if (!wasInserted) { 108 if (auto *defined = dyn_cast<Defined>(s)) { 109 if (isWeakDef) { 110 // See further comment in createDefined() in InputFiles.cpp 111 if (defined->isWeakDef()) { 112 defined->privateExtern &= isPrivateExtern; 113 defined->weakDefCanBeHidden &= isWeakDefCanBeHidden; 114 defined->referencedDynamically |= isReferencedDynamically; 115 defined->noDeadStrip |= noDeadStrip; 116 } 117 if (auto concatIsec = dyn_cast_or_null<ConcatInputSection>(isec)) { 118 concatIsec->wasCoalesced = true; 119 // Any local symbols that alias the coalesced symbol should be moved 120 // into the prevailing section. Note that we have sorted the symbols 121 // in ObjFile::parseSymbols() such that extern weak symbols appear 122 // last, so we don't need to worry about subsequent symbols being 123 // added to an already-coalesced section. 124 if (defined->isec) 125 transplantSymbolsAtOffset(concatIsec, defined->isec, 126 /*skip=*/nullptr, value, defined->value); 127 } 128 return defined; 129 } 130 131 if (defined->isWeakDef()) { 132 if (auto concatIsec = 133 dyn_cast_or_null<ConcatInputSection>(defined->isec)) { 134 concatIsec->wasCoalesced = true; 135 if (isec) 136 transplantSymbolsAtOffset(concatIsec, isec, defined, defined->value, 137 value); 138 } 139 } else { 140 std::string srcLoc1 = defined->getSourceLocation(); 141 std::string srcLoc2 = isec ? isec->getSourceLocation(value) : ""; 142 std::string srcFile1 = toString(defined->getFile()); 143 std::string srcFile2 = toString(file); 144 145 dupSymDiags.push_back({make_pair(srcLoc1, srcFile1), 146 make_pair(srcLoc2, srcFile2), defined}); 147 } 148 149 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 150 overridesWeakDef = !isWeakDef && dysym->isWeakDef(); 151 dysym->unreference(); 152 } else if (auto *undef = dyn_cast<Undefined>(s)) { 153 if (undef->wasBitcodeSymbol) { 154 auto objFile = dyn_cast<ObjFile>(file); 155 if (!objFile) { 156 // The file must be a native object file, as opposed to potentially 157 // being another bitcode file. A situation arises when some symbols 158 // are defined thru `module asm` and thus they are not present in the 159 // bitcode's symbol table. Consider bitcode modules `A`, `B`, and `C`. 160 // LTO compiles only `A` and `C`, since there's no explicit symbol 161 // reference to `B` other than a symbol from `A` via `module asm`. 162 // After LTO is finished, the missing symbol now appears in the 163 // resulting object file for `A`, which prematurely resolves another 164 // prevailing symbol with `B` that hasn't been compiled, instead of 165 // the resulting object for `C`. Consequently, an incorrect 166 // relocation is generated for the prevailing symbol. 167 assert(isa<BitcodeFile>(file) && "Bitcode file is expected."); 168 std::string message = 169 "The pending prevailing symbol(" + name.str() + 170 ") in the bitcode file(" + toString(undef->getFile()) + 171 ") is overridden by a non-native object (from bitcode): " + 172 toString(file); 173 error(message); 174 } else if (!objFile->builtFromBitcode) { 175 // Ideally, this should be an object file compiled from a bitcode 176 // file. However, this might not hold true if a LC linker option is 177 // used. In case LTO internalizes a prevailing hidden weak symbol, 178 // there's a situation where an unresolved prevailing symbol might be 179 // linked with the corresponding one from a native library, which is 180 // loaded later after LTO. Although this could potentially result in 181 // an ODR violation, we choose to permit this scenario as a warning. 182 std::string message = "The pending prevailing symbol(" + name.str() + 183 ") in the bitcode file(" + 184 toString(undef->getFile()) + 185 ") is overridden by a post-processed native " 186 "object (from native archive): " + 187 toString(file); 188 warn(message); 189 } else { 190 // Preserve the original bitcode file name (instead of using the 191 // object file name). 192 file = undef->getFile(); 193 } 194 } 195 } 196 // Defined symbols take priority over other types of symbols, so in case 197 // of a name conflict, we fall through to the replaceSymbol() call below. 198 } 199 200 // With -flat_namespace, all extern symbols in dylibs are interposable. 201 // FIXME: Add support for `-interposable` (PR53680). 202 bool interposable = config->namespaceKind == NamespaceKind::flat && 203 config->outputType != MachO::MH_EXECUTE && 204 !isPrivateExtern; 205 Defined *defined = replaceSymbol<Defined>( 206 s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true, 207 isPrivateExtern, /*includeInSymtab=*/true, isReferencedDynamically, 208 noDeadStrip, overridesWeakDef, isWeakDefCanBeHidden, interposable); 209 return defined; 210 } 211 212 Defined *SymbolTable::aliasDefined(Defined *src, StringRef target, 213 InputFile *newFile, bool makePrivateExtern) { 214 bool isPrivateExtern = makePrivateExtern || src->privateExtern; 215 return addDefined(target, newFile, src->isec, src->value, src->size, 216 src->isWeakDef(), isPrivateExtern, 217 src->referencedDynamically, src->noDeadStrip, 218 src->weakDefCanBeHidden); 219 } 220 221 Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file, 222 bool isWeakRef) { 223 auto [s, wasInserted] = insert(name, file); 224 225 RefState refState = isWeakRef ? RefState::Weak : RefState::Strong; 226 227 if (wasInserted) 228 replaceSymbol<Undefined>(s, name, file, refState, 229 /*wasBitcodeSymbol=*/false); 230 else if (auto *lazy = dyn_cast<LazyArchive>(s)) 231 lazy->fetchArchiveMember(); 232 else if (isa<LazyObject>(s)) 233 extract(*s->getFile(), s->getName()); 234 else if (auto *dynsym = dyn_cast<DylibSymbol>(s)) 235 dynsym->reference(refState); 236 else if (auto *undefined = dyn_cast<Undefined>(s)) 237 undefined->refState = std::max(undefined->refState, refState); 238 return s; 239 } 240 241 Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size, 242 uint32_t align, bool isPrivateExtern) { 243 auto [s, wasInserted] = insert(name, file); 244 245 if (!wasInserted) { 246 if (auto *common = dyn_cast<CommonSymbol>(s)) { 247 if (size < common->size) 248 return s; 249 } else if (isa<Defined>(s)) { 250 return s; 251 } 252 // Common symbols take priority over all non-Defined symbols, so in case of 253 // a name conflict, we fall through to the replaceSymbol() call below. 254 } 255 256 replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern); 257 return s; 258 } 259 260 Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef, 261 bool isTlv) { 262 auto [s, wasInserted] = insert(name, file); 263 264 RefState refState = RefState::Unreferenced; 265 if (!wasInserted) { 266 if (auto *defined = dyn_cast<Defined>(s)) { 267 if (isWeakDef && !defined->isWeakDef()) 268 defined->overridesWeakDef = true; 269 } else if (auto *undefined = dyn_cast<Undefined>(s)) { 270 refState = undefined->refState; 271 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 272 refState = dysym->getRefState(); 273 } 274 } 275 276 bool isDynamicLookup = file == nullptr; 277 if (wasInserted || isa<Undefined>(s) || 278 (isa<DylibSymbol>(s) && 279 ((!isWeakDef && s->isWeakDef()) || 280 (!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) { 281 if (auto *dynsym = dyn_cast<DylibSymbol>(s)) 282 dynsym->unreference(); 283 replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv); 284 } 285 286 return s; 287 } 288 289 Symbol *SymbolTable::addDynamicLookup(StringRef name) { 290 return addDylib(name, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false); 291 } 292 293 Symbol *SymbolTable::addLazyArchive(StringRef name, ArchiveFile *file, 294 const object::Archive::Symbol &sym) { 295 auto [s, wasInserted] = insert(name, file); 296 297 if (wasInserted) { 298 replaceSymbol<LazyArchive>(s, file, sym); 299 } else if (isa<Undefined>(s)) { 300 file->fetch(sym); 301 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 302 if (dysym->isWeakDef()) { 303 if (dysym->getRefState() != RefState::Unreferenced) 304 file->fetch(sym); 305 else 306 replaceSymbol<LazyArchive>(s, file, sym); 307 } 308 } 309 return s; 310 } 311 312 Symbol *SymbolTable::addLazyObject(StringRef name, InputFile &file) { 313 auto [s, wasInserted] = insert(name, &file); 314 315 if (wasInserted) { 316 replaceSymbol<LazyObject>(s, file, name); 317 } else if (isa<Undefined>(s)) { 318 extract(file, name); 319 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 320 if (dysym->isWeakDef()) { 321 if (dysym->getRefState() != RefState::Unreferenced) 322 extract(file, name); 323 else 324 replaceSymbol<LazyObject>(s, file, name); 325 } 326 } 327 return s; 328 } 329 330 Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec, 331 uint64_t value, bool isPrivateExtern, 332 bool includeInSymtab, 333 bool referencedDynamically) { 334 assert(!isec || !isec->getFile()); // See makeSyntheticInputSection(). 335 Defined *s = addDefined(name, /*file=*/nullptr, isec, value, /*size=*/0, 336 /*isWeakDef=*/false, isPrivateExtern, 337 referencedDynamically, /*noDeadStrip=*/false, 338 /*isWeakDefCanBeHidden=*/false); 339 s->includeInSymtab = includeInSymtab; 340 return s; 341 } 342 343 enum class Boundary { 344 Start, 345 End, 346 }; 347 348 static Defined *createBoundarySymbol(const Undefined &sym) { 349 return symtab->addSynthetic( 350 sym.getName(), /*isec=*/nullptr, /*value=*/-1, /*isPrivateExtern=*/true, 351 /*includeInSymtab=*/false, /*referencedDynamically=*/false); 352 } 353 354 static void handleSectionBoundarySymbol(const Undefined &sym, StringRef segSect, 355 Boundary which) { 356 auto [segName, sectName] = segSect.split('$'); 357 358 // Attach the symbol to any InputSection that will end up in the right 359 // OutputSection -- it doesn't matter which one we pick. 360 // Don't bother looking through inputSections for a matching 361 // ConcatInputSection -- we need to create ConcatInputSection for 362 // non-existing sections anyways, and that codepath works even if we should 363 // already have a ConcatInputSection with the right name. 364 365 OutputSection *osec = nullptr; 366 // This looks for __TEXT,__cstring etc. 367 for (SyntheticSection *ssec : syntheticSections) 368 if (ssec->segname == segName && ssec->name == sectName) { 369 osec = ssec->isec->parent; 370 break; 371 } 372 373 if (!osec) { 374 ConcatInputSection *isec = makeSyntheticInputSection(segName, sectName); 375 376 // This runs after markLive() and is only called for Undefineds that are 377 // live. Marking the isec live ensures an OutputSection is created that the 378 // start/end symbol can refer to. 379 assert(sym.isLive()); 380 isec->live = true; 381 382 // This runs after gatherInputSections(), so need to explicitly set parent 383 // and add to inputSections. 384 osec = isec->parent = ConcatOutputSection::getOrCreateForInput(isec); 385 inputSections.push_back(isec); 386 } 387 388 if (which == Boundary::Start) 389 osec->sectionStartSymbols.push_back(createBoundarySymbol(sym)); 390 else 391 osec->sectionEndSymbols.push_back(createBoundarySymbol(sym)); 392 } 393 394 static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName, 395 Boundary which) { 396 OutputSegment *seg = getOrCreateOutputSegment(segName); 397 if (which == Boundary::Start) 398 seg->segmentStartSymbols.push_back(createBoundarySymbol(sym)); 399 else 400 seg->segmentEndSymbols.push_back(createBoundarySymbol(sym)); 401 } 402 403 // Try to find a definition for an undefined symbol. 404 // Returns true if a definition was found and no diagnostics are needed. 405 static bool recoverFromUndefinedSymbol(const Undefined &sym) { 406 // Handle start/end symbols. 407 StringRef name = sym.getName(); 408 if (name.consume_front("section$start$")) { 409 handleSectionBoundarySymbol(sym, name, Boundary::Start); 410 return true; 411 } 412 if (name.consume_front("section$end$")) { 413 handleSectionBoundarySymbol(sym, name, Boundary::End); 414 return true; 415 } 416 if (name.consume_front("segment$start$")) { 417 handleSegmentBoundarySymbol(sym, name, Boundary::Start); 418 return true; 419 } 420 if (name.consume_front("segment$end$")) { 421 handleSegmentBoundarySymbol(sym, name, Boundary::End); 422 return true; 423 } 424 425 // Leave dtrace symbols, since we will handle them when we do the relocation 426 if (name.starts_with("___dtrace_")) 427 return true; 428 429 // Handle -U. 430 if (config->explicitDynamicLookups.count(sym.getName())) { 431 symtab->addDynamicLookup(sym.getName()); 432 return true; 433 } 434 435 // Handle -undefined. 436 if (config->undefinedSymbolTreatment == 437 UndefinedSymbolTreatment::dynamic_lookup || 438 config->undefinedSymbolTreatment == UndefinedSymbolTreatment::suppress) { 439 symtab->addDynamicLookup(sym.getName()); 440 return true; 441 } 442 443 // We do not return true here, as we still need to print diagnostics. 444 if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::warning) 445 symtab->addDynamicLookup(sym.getName()); 446 447 return false; 448 } 449 450 namespace { 451 struct UndefinedDiag { 452 struct SectionAndOffset { 453 const InputSection *isec; 454 uint64_t offset; 455 }; 456 457 std::vector<SectionAndOffset> codeReferences; 458 std::vector<std::string> otherReferences; 459 }; 460 461 MapVector<const Undefined *, UndefinedDiag> undefs; 462 } // namespace 463 464 void macho::reportPendingDuplicateSymbols() { 465 for (const auto &duplicate : dupSymDiags) { 466 if (!config->deadStripDuplicates || duplicate.sym->isLive()) { 467 std::string message = 468 "duplicate symbol: " + toString(*duplicate.sym) + "\n>>> defined in "; 469 if (!duplicate.src1.first.empty()) 470 message += duplicate.src1.first + "\n>>> "; 471 message += duplicate.src1.second + "\n>>> defined in "; 472 if (!duplicate.src2.first.empty()) 473 message += duplicate.src2.first + "\n>>> "; 474 error(message + duplicate.src2.second); 475 } 476 } 477 } 478 479 // Check whether the definition name def is a mangled function name that matches 480 // the reference name ref. 481 static bool canSuggestExternCForCXX(StringRef ref, StringRef def) { 482 llvm::ItaniumPartialDemangler d; 483 std::string name = def.str(); 484 if (d.partialDemangle(name.c_str())) 485 return false; 486 char *buf = d.getFunctionName(nullptr, nullptr); 487 if (!buf) 488 return false; 489 bool ret = ref == buf; 490 free(buf); 491 return ret; 492 } 493 494 // Suggest an alternative spelling of an "undefined symbol" diagnostic. Returns 495 // the suggested symbol, which is either in the symbol table, or in the same 496 // file of sym. 497 static const Symbol *getAlternativeSpelling(const Undefined &sym, 498 std::string &preHint, 499 std::string &postHint) { 500 DenseMap<StringRef, const Symbol *> map; 501 if (sym.getFile() && sym.getFile()->kind() == InputFile::ObjKind) { 502 // Build a map of local defined symbols. 503 for (const Symbol *s : sym.getFile()->symbols) 504 if (auto *defined = dyn_cast_or_null<Defined>(s)) 505 if (!defined->isExternal()) 506 map.try_emplace(s->getName(), s); 507 } 508 509 auto suggest = [&](StringRef newName) -> const Symbol * { 510 // If defined locally. 511 if (const Symbol *s = map.lookup(newName)) 512 return s; 513 514 // If in the symbol table and not undefined. 515 if (const Symbol *s = symtab->find(newName)) 516 if (dyn_cast<Undefined>(s) == nullptr) 517 return s; 518 519 return nullptr; 520 }; 521 522 // This loop enumerates all strings of Levenshtein distance 1 as typo 523 // correction candidates and suggests the one that exists as a non-undefined 524 // symbol. 525 StringRef name = sym.getName(); 526 for (size_t i = 0, e = name.size(); i != e + 1; ++i) { 527 // Insert a character before name[i]. 528 std::string newName = (name.substr(0, i) + "0" + name.substr(i)).str(); 529 for (char c = '0'; c <= 'z'; ++c) { 530 newName[i] = c; 531 if (const Symbol *s = suggest(newName)) 532 return s; 533 } 534 if (i == e) 535 break; 536 537 // Substitute name[i]. 538 newName = std::string(name); 539 for (char c = '0'; c <= 'z'; ++c) { 540 newName[i] = c; 541 if (const Symbol *s = suggest(newName)) 542 return s; 543 } 544 545 // Transpose name[i] and name[i+1]. This is of edit distance 2 but it is 546 // common. 547 if (i + 1 < e) { 548 newName[i] = name[i + 1]; 549 newName[i + 1] = name[i]; 550 if (const Symbol *s = suggest(newName)) 551 return s; 552 } 553 554 // Delete name[i]. 555 newName = (name.substr(0, i) + name.substr(i + 1)).str(); 556 if (const Symbol *s = suggest(newName)) 557 return s; 558 } 559 560 // Case mismatch, e.g. Foo vs FOO. 561 for (auto &it : map) 562 if (name.equals_insensitive(it.first)) 563 return it.second; 564 for (Symbol *sym : symtab->getSymbols()) 565 if (dyn_cast<Undefined>(sym) == nullptr && 566 name.equals_insensitive(sym->getName())) 567 return sym; 568 569 // The reference may be a mangled name while the definition is not. Suggest a 570 // missing extern "C". 571 if (name.starts_with("__Z")) { 572 std::string buf = name.str(); 573 llvm::ItaniumPartialDemangler d; 574 if (!d.partialDemangle(buf.c_str())) 575 if (char *buf = d.getFunctionName(nullptr, nullptr)) { 576 const Symbol *s = suggest((Twine("_") + buf).str()); 577 free(buf); 578 if (s) { 579 preHint = ": extern \"C\" "; 580 return s; 581 } 582 } 583 } else { 584 StringRef nameWithoutUnderscore = name; 585 nameWithoutUnderscore.consume_front("_"); 586 const Symbol *s = nullptr; 587 for (auto &it : map) 588 if (canSuggestExternCForCXX(nameWithoutUnderscore, it.first)) { 589 s = it.second; 590 break; 591 } 592 if (!s) 593 for (Symbol *sym : symtab->getSymbols()) 594 if (canSuggestExternCForCXX(nameWithoutUnderscore, sym->getName())) { 595 s = sym; 596 break; 597 } 598 if (s) { 599 preHint = " to declare "; 600 postHint = " as extern \"C\"?"; 601 return s; 602 } 603 } 604 605 return nullptr; 606 } 607 608 static void reportUndefinedSymbol(const Undefined &sym, 609 const UndefinedDiag &locations, 610 bool correctSpelling) { 611 std::string message = "undefined symbol"; 612 if (config->archMultiple) 613 message += (" for arch " + getArchitectureName(config->arch())).str(); 614 message += ": " + toString(sym); 615 616 const size_t maxUndefinedReferences = 3; 617 size_t i = 0; 618 for (const std::string &loc : locations.otherReferences) { 619 if (i >= maxUndefinedReferences) 620 break; 621 message += "\n>>> referenced by " + loc; 622 ++i; 623 } 624 625 for (const UndefinedDiag::SectionAndOffset &loc : locations.codeReferences) { 626 if (i >= maxUndefinedReferences) 627 break; 628 message += "\n>>> referenced by "; 629 std::string src = loc.isec->getSourceLocation(loc.offset); 630 if (!src.empty()) 631 message += src + "\n>>> "; 632 message += loc.isec->getLocation(loc.offset); 633 ++i; 634 } 635 636 size_t totalReferences = 637 locations.otherReferences.size() + locations.codeReferences.size(); 638 if (totalReferences > i) 639 message += 640 ("\n>>> referenced " + Twine(totalReferences - i) + " more times") 641 .str(); 642 643 if (correctSpelling) { 644 std::string preHint = ": ", postHint; 645 if (const Symbol *corrected = 646 getAlternativeSpelling(sym, preHint, postHint)) { 647 message += 648 "\n>>> did you mean" + preHint + toString(*corrected) + postHint; 649 if (corrected->getFile()) 650 message += "\n>>> defined in: " + toString(corrected->getFile()); 651 } 652 } 653 654 if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::error) 655 error(message); 656 else if (config->undefinedSymbolTreatment == 657 UndefinedSymbolTreatment::warning) 658 warn(message); 659 else 660 assert(false && "diagnostics make sense for -undefined error|warning only"); 661 } 662 663 void macho::reportPendingUndefinedSymbols() { 664 // Enable spell corrector for the first 2 diagnostics. 665 for (const auto &[i, undef] : llvm::enumerate(undefs)) 666 reportUndefinedSymbol(*undef.first, undef.second, i < 2); 667 668 // This function is called multiple times during execution. Clear the printed 669 // diagnostics to avoid printing the same things again the next time. 670 undefs.clear(); 671 } 672 673 void macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) { 674 if (recoverFromUndefinedSymbol(sym)) 675 return; 676 677 undefs[&sym].otherReferences.push_back(source.str()); 678 } 679 680 void macho::treatUndefinedSymbol(const Undefined &sym, const InputSection *isec, 681 uint64_t offset) { 682 if (recoverFromUndefinedSymbol(sym)) 683 return; 684 685 undefs[&sym].codeReferences.push_back({isec, offset}); 686 } 687 688 std::unique_ptr<SymbolTable> macho::symtab; 689