1 //===- SymbolTable.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "SymbolTable.h"
10 #include "ConcatOutputSection.h"
12 #include "InputFiles.h"
13 #include "InputSection.h"
15 #include "SyntheticSections.h"
16 #include "lld/Common/ErrorHandler.h"
17 #include "lld/Common/Memory.h"
18 #include "llvm/Demangle/Demangle.h"
22 using namespace lld::macho
;
24 Symbol
*SymbolTable::find(CachedHashStringRef cachedName
) {
25 auto it
= symMap
.find(cachedName
);
26 if (it
== symMap
.end())
28 return symVector
[it
->second
];
31 std::pair
<Symbol
*, bool> SymbolTable::insert(StringRef name
,
32 const InputFile
*file
) {
33 auto p
= symMap
.insert({CachedHashStringRef(name
), (int)symVector
.size()});
37 // Name already present in the symbol table.
38 sym
= symVector
[p
.first
->second
];
40 // Name is a new symbol.
41 sym
= reinterpret_cast<Symbol
*>(make
<SymbolUnion
>());
42 symVector
.push_back(sym
);
45 sym
->isUsedInRegularObj
|= !file
|| isa
<ObjFile
>(file
);
46 return {sym
, p
.second
};
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
;
56 DuplicateSymbolDiag(const std::pair
<std::string
, std::string
> src1
,
57 const std::pair
<std::string
, std::string
> src2
,
59 : src1(src1
), src2(src2
), sym(sym
) {}
61 SmallVector
<DuplicateSymbolDiag
> dupSymDiags
;
64 // Move symbols at \p fromOff in \p fromIsec into \p toIsec, unless that symbol
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
;
74 llvm::erase_if(fromIsec
->symbols
, [&](Symbol
*s
) {
75 auto *d
= cast
<Defined
>(s
);
76 if (d
->value
!= fromOff
)
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
->originalIsec
= toIsec
;
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
->originalUnwindEntry
= nullptr;
96 Defined
*SymbolTable::addDefined(StringRef name
, InputFile
*file
,
97 InputSection
*isec
, uint64_t value
,
98 uint64_t size
, bool isWeakDef
,
100 bool isReferencedDynamically
, bool noDeadStrip
,
101 bool isWeakDefCanBeHidden
) {
102 bool overridesWeakDef
= false;
103 auto [s
, wasInserted
] = insert(name
, file
);
105 assert(!file
|| !isa
<BitcodeFile
>(file
) || !isec
);
108 if (auto *defined
= dyn_cast
<Defined
>(s
)) {
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
;
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.
125 transplantSymbolsAtOffset(concatIsec
, defined
->isec(),
126 /*skip=*/nullptr, value
, defined
->value
);
131 if (defined
->isWeakDef()) {
132 if (auto concatIsec
=
133 dyn_cast_or_null
<ConcatInputSection
>(defined
->isec())) {
134 concatIsec
->wasCoalesced
= true;
136 transplantSymbolsAtOffset(concatIsec
, isec
, defined
, defined
->value
,
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
);
145 dupSymDiags
.push_back({make_pair(srcLoc1
, srcFile1
),
146 make_pair(srcLoc2
, srcFile2
), defined
});
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
);
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): " +
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): " +
190 // Preserve the original bitcode file name (instead of using the
191 // object file name).
192 file
= undef
->getFile();
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.
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
&&
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
);
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
);
221 Symbol
*SymbolTable::addUndefined(StringRef name
, InputFile
*file
,
223 auto [s
, wasInserted
] = insert(name
, file
);
225 RefState refState
= isWeakRef
? RefState::Weak
: RefState::Strong
;
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
);
241 Symbol
*SymbolTable::addCommon(StringRef name
, InputFile
*file
, uint64_t size
,
242 uint32_t align
, bool isPrivateExtern
) {
243 auto [s
, wasInserted
] = insert(name
, file
);
246 if (auto *common
= dyn_cast
<CommonSymbol
>(s
)) {
247 if (size
< common
->size
)
249 } else if (isa
<Defined
>(s
)) {
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.
256 replaceSymbol
<CommonSymbol
>(s
, name
, file
, size
, align
, isPrivateExtern
);
260 Symbol
*SymbolTable::addDylib(StringRef name
, DylibFile
*file
, bool isWeakDef
,
262 auto [s
, wasInserted
] = insert(name
, file
);
264 RefState refState
= RefState::Unreferenced
;
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();
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
);
289 Symbol
*SymbolTable::addDynamicLookup(StringRef name
) {
290 return addDylib(name
, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false);
293 Symbol
*SymbolTable::addLazyArchive(StringRef name
, ArchiveFile
*file
,
294 const object::Archive::Symbol
&sym
) {
295 auto [s
, wasInserted
] = insert(name
, file
);
298 replaceSymbol
<LazyArchive
>(s
, file
, sym
);
299 } else if (isa
<Undefined
>(s
)) {
301 } else if (auto *dysym
= dyn_cast
<DylibSymbol
>(s
)) {
302 if (dysym
->isWeakDef()) {
303 if (dysym
->getRefState() != RefState::Unreferenced
)
306 replaceSymbol
<LazyArchive
>(s
, file
, sym
);
312 Symbol
*SymbolTable::addLazyObject(StringRef name
, InputFile
&file
) {
313 auto [s
, wasInserted
] = insert(name
, &file
);
316 replaceSymbol
<LazyObject
>(s
, file
, name
);
317 } else if (isa
<Undefined
>(s
)) {
319 } else if (auto *dysym
= dyn_cast
<DylibSymbol
>(s
)) {
320 if (dysym
->isWeakDef()) {
321 if (dysym
->getRefState() != RefState::Unreferenced
)
324 replaceSymbol
<LazyObject
>(s
, file
, name
);
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
;
343 enum class Boundary
{
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);
354 static void handleSectionBoundarySymbol(const Undefined
&sym
, StringRef segSect
,
356 auto [segName
, sectName
] = segSect
.split('$');
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.
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
;
374 ConcatInputSection
*isec
= makeSyntheticInputSection(segName
, sectName
);
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());
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
);
388 if (which
== Boundary::Start
)
389 osec
->sectionStartSymbols
.push_back(createBoundarySymbol(sym
));
391 osec
->sectionEndSymbols
.push_back(createBoundarySymbol(sym
));
394 static void handleSegmentBoundarySymbol(const Undefined
&sym
, StringRef segName
,
396 OutputSegment
*seg
= getOrCreateOutputSegment(segName
);
397 if (which
== Boundary::Start
)
398 seg
->segmentStartSymbols
.push_back(createBoundarySymbol(sym
));
400 seg
->segmentEndSymbols
.push_back(createBoundarySymbol(sym
));
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
);
412 if (name
.consume_front("section$end$")) {
413 handleSectionBoundarySymbol(sym
, name
, Boundary::End
);
416 if (name
.consume_front("segment$start$")) {
417 handleSegmentBoundarySymbol(sym
, name
, Boundary::Start
);
420 if (name
.consume_front("segment$end$")) {
421 handleSegmentBoundarySymbol(sym
, name
, Boundary::End
);
425 // Leave dtrace symbols, since we will handle them when we do the relocation
426 if (name
.starts_with("___dtrace_"))
430 if (config
->explicitDynamicLookups
.count(sym
.getName())) {
431 symtab
->addDynamicLookup(sym
.getName());
435 // Handle -undefined.
436 if (config
->undefinedSymbolTreatment
==
437 UndefinedSymbolTreatment::dynamic_lookup
||
438 config
->undefinedSymbolTreatment
== UndefinedSymbolTreatment::suppress
) {
439 symtab
->addDynamicLookup(sym
.getName());
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());
451 struct UndefinedDiag
{
452 struct SectionAndOffset
{
453 const InputSection
*isec
;
457 std::vector
<SectionAndOffset
> codeReferences
;
458 std::vector
<std::string
> otherReferences
;
461 MapVector
<const Undefined
*, UndefinedDiag
> undefs
;
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
);
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()))
486 char *buf
= d
.getFunctionName(nullptr, nullptr);
489 bool ret
= ref
== buf
;
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
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
);
509 auto suggest
= [&](StringRef newName
) -> const Symbol
* {
510 // If defined locally.
511 if (const Symbol
*s
= map
.lookup(newName
))
514 // If in the symbol table and not undefined.
515 if (const Symbol
*s
= symtab
->find(newName
))
516 if (dyn_cast
<Undefined
>(s
) == nullptr)
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
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
) {
531 if (const Symbol
*s
= suggest(newName
))
537 // Substitute name[i].
538 newName
= std::string(name
);
539 for (char c
= '0'; c
<= 'z'; ++c
) {
541 if (const Symbol
*s
= suggest(newName
))
545 // Transpose name[i] and name[i+1]. This is of edit distance 2 but it is
548 newName
[i
] = name
[i
+ 1];
549 newName
[i
+ 1] = name
[i
];
550 if (const Symbol
*s
= suggest(newName
))
555 newName
= (name
.substr(0, i
) + name
.substr(i
+ 1)).str();
556 if (const Symbol
*s
= suggest(newName
))
560 // Case mismatch, e.g. Foo vs FOO.
562 if (name
.equals_insensitive(it
.first
))
564 for (Symbol
*sym
: symtab
->getSymbols())
565 if (dyn_cast
<Undefined
>(sym
) == nullptr &&
566 name
.equals_insensitive(sym
->getName()))
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());
579 preHint
= ": extern \"C\" ";
584 StringRef nameWithoutUnderscore
= name
;
585 nameWithoutUnderscore
.consume_front("_");
586 const Symbol
*s
= nullptr;
588 if (canSuggestExternCForCXX(nameWithoutUnderscore
, it
.first
)) {
593 for (Symbol
*sym
: symtab
->getSymbols())
594 if (canSuggestExternCForCXX(nameWithoutUnderscore
, sym
->getName())) {
599 preHint
= " to declare ";
600 postHint
= " as extern \"C\"?";
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
);
616 const size_t maxUndefinedReferences
= 3;
618 for (const std::string
&loc
: locations
.otherReferences
) {
619 if (i
>= maxUndefinedReferences
)
621 message
+= "\n>>> referenced by " + loc
;
625 for (const UndefinedDiag::SectionAndOffset
&loc
: locations
.codeReferences
) {
626 if (i
>= maxUndefinedReferences
)
628 message
+= "\n>>> referenced by ";
629 std::string src
= loc
.isec
->getSourceLocation(loc
.offset
);
631 message
+= src
+ "\n>>> ";
632 message
+= loc
.isec
->getLocation(loc
.offset
);
636 size_t totalReferences
=
637 locations
.otherReferences
.size() + locations
.codeReferences
.size();
638 if (totalReferences
> i
)
640 ("\n>>> referenced " + Twine(totalReferences
- i
) + " more times")
643 if (correctSpelling
) {
644 std::string preHint
= ": ", postHint
;
645 if (const Symbol
*corrected
=
646 getAlternativeSpelling(sym
, preHint
, postHint
)) {
648 "\n>>> did you mean" + preHint
+ toString(*corrected
) + postHint
;
649 if (corrected
->getFile())
650 message
+= "\n>>> defined in: " + toString(corrected
->getFile());
654 if (config
->undefinedSymbolTreatment
== UndefinedSymbolTreatment::error
)
656 else if (config
->undefinedSymbolTreatment
==
657 UndefinedSymbolTreatment::warning
)
660 assert(false && "diagnostics make sense for -undefined error|warning only");
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);
668 // This function is called multiple times during execution. Clear the printed
669 // diagnostics to avoid printing the same things again the next time.
673 void macho::treatUndefinedSymbol(const Undefined
&sym
, StringRef source
) {
674 if (recoverFromUndefinedSymbol(sym
))
677 undefs
[&sym
].otherReferences
.push_back(source
.str());
680 void macho::treatUndefinedSymbol(const Undefined
&sym
, const InputSection
*isec
,
682 if (recoverFromUndefinedSymbol(sym
))
685 undefs
[&sym
].codeReferences
.push_back({isec
, offset
});
688 std::unique_ptr
<SymbolTable
> macho::symtab
;