xref: /openbsd/gnu/llvm/lld/MachO/SymbolTable.cpp (revision dfe94b16)
1bb684c34Spatrick //===- SymbolTable.cpp ----------------------------------------------------===//
2bb684c34Spatrick //
3bb684c34Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bb684c34Spatrick // See https://llvm.org/LICENSE.txt for license information.
5bb684c34Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bb684c34Spatrick //
7bb684c34Spatrick //===----------------------------------------------------------------------===//
8bb684c34Spatrick 
9bb684c34Spatrick #include "SymbolTable.h"
101cf9926bSpatrick #include "ConcatOutputSection.h"
111cf9926bSpatrick #include "Config.h"
12bb684c34Spatrick #include "InputFiles.h"
13*dfe94b16Srobert #include "InputSection.h"
14bb684c34Spatrick #include "Symbols.h"
151cf9926bSpatrick #include "SyntheticSections.h"
16bb684c34Spatrick #include "lld/Common/ErrorHandler.h"
17bb684c34Spatrick #include "lld/Common/Memory.h"
18*dfe94b16Srobert #include "llvm/Demangle/Demangle.h"
19bb684c34Spatrick 
20bb684c34Spatrick using namespace llvm;
21bb684c34Spatrick using namespace lld;
22bb684c34Spatrick using namespace lld::macho;
23bb684c34Spatrick 
find(CachedHashStringRef cachedName)241cf9926bSpatrick Symbol *SymbolTable::find(CachedHashStringRef cachedName) {
251cf9926bSpatrick   auto it = symMap.find(cachedName);
26bb684c34Spatrick   if (it == symMap.end())
27bb684c34Spatrick     return nullptr;
28bb684c34Spatrick   return symVector[it->second];
29bb684c34Spatrick }
30bb684c34Spatrick 
insert(StringRef name,const InputFile * file)311cf9926bSpatrick std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
321cf9926bSpatrick                                               const InputFile *file) {
33bb684c34Spatrick   auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
34bb684c34Spatrick 
351cf9926bSpatrick   Symbol *sym;
361cf9926bSpatrick   if (!p.second) {
37bb684c34Spatrick     // Name already present in the symbol table.
381cf9926bSpatrick     sym = symVector[p.first->second];
391cf9926bSpatrick   } else {
40bb684c34Spatrick     // Name is a new symbol.
411cf9926bSpatrick     sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
42bb684c34Spatrick     symVector.push_back(sym);
43bb684c34Spatrick   }
44bb684c34Spatrick 
451cf9926bSpatrick   sym->isUsedInRegularObj |= !file || isa<ObjFile>(file);
461cf9926bSpatrick   return {sym, p.second};
47bb684c34Spatrick }
48bb684c34Spatrick 
49*dfe94b16Srobert namespace {
50*dfe94b16Srobert struct DuplicateSymbolDiag {
51*dfe94b16Srobert   // Pair containing source location and source file
52*dfe94b16Srobert   const std::pair<std::string, std::string> src1;
53*dfe94b16Srobert   const std::pair<std::string, std::string> src2;
54*dfe94b16Srobert   const Symbol *sym;
55*dfe94b16Srobert 
DuplicateSymbolDiag__anond2af162d0111::DuplicateSymbolDiag56*dfe94b16Srobert   DuplicateSymbolDiag(const std::pair<std::string, std::string> src1,
57*dfe94b16Srobert                       const std::pair<std::string, std::string> src2,
58*dfe94b16Srobert                       const Symbol *sym)
59*dfe94b16Srobert       : src1(src1), src2(src2), sym(sym) {}
60*dfe94b16Srobert };
61*dfe94b16Srobert SmallVector<DuplicateSymbolDiag> dupSymDiags;
62*dfe94b16Srobert } // namespace
63*dfe94b16Srobert 
addDefined(StringRef name,InputFile * file,InputSection * isec,uint64_t value,uint64_t size,bool isWeakDef,bool isPrivateExtern,bool isThumb,bool isReferencedDynamically,bool noDeadStrip,bool isWeakDefCanBeHidden)641cf9926bSpatrick Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
651cf9926bSpatrick                                  InputSection *isec, uint64_t value,
661cf9926bSpatrick                                  uint64_t size, bool isWeakDef,
671cf9926bSpatrick                                  bool isPrivateExtern, bool isThumb,
68*dfe94b16Srobert                                  bool isReferencedDynamically, bool noDeadStrip,
69*dfe94b16Srobert                                  bool isWeakDefCanBeHidden) {
701cf9926bSpatrick   bool overridesWeakDef = false;
71*dfe94b16Srobert   auto [s, wasInserted] = insert(name, file);
721cf9926bSpatrick 
73*dfe94b16Srobert   assert(!file || !isa<BitcodeFile>(file) || !isec);
741cf9926bSpatrick 
751cf9926bSpatrick   if (!wasInserted) {
761cf9926bSpatrick     if (auto *defined = dyn_cast<Defined>(s)) {
771cf9926bSpatrick       if (isWeakDef) {
78*dfe94b16Srobert         // See further comment in createDefined() in InputFiles.cpp
791cf9926bSpatrick         if (defined->isWeakDef()) {
801cf9926bSpatrick           defined->privateExtern &= isPrivateExtern;
81*dfe94b16Srobert           defined->weakDefCanBeHidden &= isWeakDefCanBeHidden;
821cf9926bSpatrick           defined->referencedDynamically |= isReferencedDynamically;
831cf9926bSpatrick           defined->noDeadStrip |= noDeadStrip;
84*dfe94b16Srobert         }
851cf9926bSpatrick         // FIXME: Handle this for bitcode files.
861cf9926bSpatrick         if (auto concatIsec = dyn_cast_or_null<ConcatInputSection>(isec))
871cf9926bSpatrick           concatIsec->wasCoalesced = true;
881cf9926bSpatrick         return defined;
891cf9926bSpatrick       }
90*dfe94b16Srobert 
91*dfe94b16Srobert       if (defined->isWeakDef()) {
92*dfe94b16Srobert         // FIXME: Handle this for bitcode files.
93*dfe94b16Srobert         if (auto concatIsec =
94*dfe94b16Srobert                 dyn_cast_or_null<ConcatInputSection>(defined->isec)) {
95*dfe94b16Srobert           concatIsec->wasCoalesced = true;
96*dfe94b16Srobert           concatIsec->symbols.erase(llvm::find(concatIsec->symbols, defined));
97*dfe94b16Srobert         }
98*dfe94b16Srobert       } else {
99*dfe94b16Srobert         std::string srcLoc1 = defined->getSourceLocation();
100*dfe94b16Srobert         std::string srcLoc2 = isec ? isec->getSourceLocation(value) : "";
101*dfe94b16Srobert         std::string srcFile1 = toString(defined->getFile());
102*dfe94b16Srobert         std::string srcFile2 = toString(file);
103*dfe94b16Srobert 
104*dfe94b16Srobert         dupSymDiags.push_back({make_pair(srcLoc1, srcFile1),
105*dfe94b16Srobert                                make_pair(srcLoc2, srcFile2), defined});
106*dfe94b16Srobert       }
107*dfe94b16Srobert 
1081cf9926bSpatrick     } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
1091cf9926bSpatrick       overridesWeakDef = !isWeakDef && dysym->isWeakDef();
1101cf9926bSpatrick       dysym->unreference();
111*dfe94b16Srobert     } else if (auto *undef = dyn_cast<Undefined>(s)) {
112*dfe94b16Srobert       // Preserve the original bitcode file name (instead of using the object
113*dfe94b16Srobert       // file name).
114*dfe94b16Srobert       if (undef->wasBitcodeSymbol)
115*dfe94b16Srobert         file = undef->getFile();
1161cf9926bSpatrick     }
1171cf9926bSpatrick     // Defined symbols take priority over other types of symbols, so in case
1181cf9926bSpatrick     // of a name conflict, we fall through to the replaceSymbol() call below.
1191cf9926bSpatrick   }
1201cf9926bSpatrick 
121*dfe94b16Srobert   // With -flat_namespace, all extern symbols in dylibs are interposable.
122*dfe94b16Srobert   // FIXME: Add support for `-interposable` (PR53680).
123*dfe94b16Srobert   bool interposable = config->namespaceKind == NamespaceKind::flat &&
124*dfe94b16Srobert                       config->outputType != MachO::MH_EXECUTE &&
125*dfe94b16Srobert                       !isPrivateExtern;
1261cf9926bSpatrick   Defined *defined = replaceSymbol<Defined>(
1271cf9926bSpatrick       s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
128*dfe94b16Srobert       isPrivateExtern, /*includeInSymtab=*/true, isThumb,
129*dfe94b16Srobert       isReferencedDynamically, noDeadStrip, overridesWeakDef,
130*dfe94b16Srobert       isWeakDefCanBeHidden, interposable);
1311cf9926bSpatrick   return defined;
1321cf9926bSpatrick }
1331cf9926bSpatrick 
aliasDefined(Defined * src,StringRef target,InputFile * newFile,bool makePrivateExtern)134*dfe94b16Srobert Defined *SymbolTable::aliasDefined(Defined *src, StringRef target,
135*dfe94b16Srobert                                    InputFile *newFile, bool makePrivateExtern) {
136*dfe94b16Srobert   bool isPrivateExtern = makePrivateExtern || src->privateExtern;
137*dfe94b16Srobert   return addDefined(target, newFile, src->isec, src->value, src->size,
138*dfe94b16Srobert                     src->isWeakDef(), isPrivateExtern, src->thumb,
139*dfe94b16Srobert                     src->referencedDynamically, src->noDeadStrip,
140*dfe94b16Srobert                     src->weakDefCanBeHidden);
141*dfe94b16Srobert }
142*dfe94b16Srobert 
addUndefined(StringRef name,InputFile * file,bool isWeakRef)1431cf9926bSpatrick Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file,
1441cf9926bSpatrick                                   bool isWeakRef) {
145*dfe94b16Srobert   auto [s, wasInserted] = insert(name, file);
1461cf9926bSpatrick 
1471cf9926bSpatrick   RefState refState = isWeakRef ? RefState::Weak : RefState::Strong;
148bb684c34Spatrick 
149bb684c34Spatrick   if (wasInserted)
150*dfe94b16Srobert     replaceSymbol<Undefined>(s, name, file, refState,
151*dfe94b16Srobert                              /*wasBitcodeSymbol=*/false);
152*dfe94b16Srobert   else if (auto *lazy = dyn_cast<LazyArchive>(s))
153bb684c34Spatrick     lazy->fetchArchiveMember();
154*dfe94b16Srobert   else if (isa<LazyObject>(s))
155*dfe94b16Srobert     extract(*s->getFile(), s->getName());
1561cf9926bSpatrick   else if (auto *dynsym = dyn_cast<DylibSymbol>(s))
1571cf9926bSpatrick     dynsym->reference(refState);
1581cf9926bSpatrick   else if (auto *undefined = dyn_cast<Undefined>(s))
1591cf9926bSpatrick     undefined->refState = std::max(undefined->refState, refState);
160bb684c34Spatrick   return s;
161bb684c34Spatrick }
162bb684c34Spatrick 
addCommon(StringRef name,InputFile * file,uint64_t size,uint32_t align,bool isPrivateExtern)1631cf9926bSpatrick Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size,
1641cf9926bSpatrick                                uint32_t align, bool isPrivateExtern) {
165*dfe94b16Srobert   auto [s, wasInserted] = insert(name, file);
166bb684c34Spatrick 
1671cf9926bSpatrick   if (!wasInserted) {
1681cf9926bSpatrick     if (auto *common = dyn_cast<CommonSymbol>(s)) {
1691cf9926bSpatrick       if (size < common->size)
170bb684c34Spatrick         return s;
1711cf9926bSpatrick     } else if (isa<Defined>(s)) {
1721cf9926bSpatrick       return s;
1731cf9926bSpatrick     }
1741cf9926bSpatrick     // Common symbols take priority over all non-Defined symbols, so in case of
1751cf9926bSpatrick     // a name conflict, we fall through to the replaceSymbol() call below.
1761cf9926bSpatrick   }
1771cf9926bSpatrick 
1781cf9926bSpatrick   replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern);
1791cf9926bSpatrick   return s;
1801cf9926bSpatrick }
1811cf9926bSpatrick 
addDylib(StringRef name,DylibFile * file,bool isWeakDef,bool isTlv)1821cf9926bSpatrick Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef,
1831cf9926bSpatrick                               bool isTlv) {
184*dfe94b16Srobert   auto [s, wasInserted] = insert(name, file);
1851cf9926bSpatrick 
1861cf9926bSpatrick   RefState refState = RefState::Unreferenced;
1871cf9926bSpatrick   if (!wasInserted) {
1881cf9926bSpatrick     if (auto *defined = dyn_cast<Defined>(s)) {
1891cf9926bSpatrick       if (isWeakDef && !defined->isWeakDef())
1901cf9926bSpatrick         defined->overridesWeakDef = true;
1911cf9926bSpatrick     } else if (auto *undefined = dyn_cast<Undefined>(s)) {
1921cf9926bSpatrick       refState = undefined->refState;
1931cf9926bSpatrick     } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
1941cf9926bSpatrick       refState = dysym->getRefState();
1951cf9926bSpatrick     }
1961cf9926bSpatrick   }
1971cf9926bSpatrick 
1981cf9926bSpatrick   bool isDynamicLookup = file == nullptr;
1991cf9926bSpatrick   if (wasInserted || isa<Undefined>(s) ||
2001cf9926bSpatrick       (isa<DylibSymbol>(s) &&
2011cf9926bSpatrick        ((!isWeakDef && s->isWeakDef()) ||
2021cf9926bSpatrick         (!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) {
2031cf9926bSpatrick     if (auto *dynsym = dyn_cast<DylibSymbol>(s))
2041cf9926bSpatrick       dynsym->unreference();
2051cf9926bSpatrick     replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv);
2061cf9926bSpatrick   }
2071cf9926bSpatrick 
2081cf9926bSpatrick   return s;
2091cf9926bSpatrick }
2101cf9926bSpatrick 
addDynamicLookup(StringRef name)2111cf9926bSpatrick Symbol *SymbolTable::addDynamicLookup(StringRef name) {
2121cf9926bSpatrick   return addDylib(name, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false);
213bb684c34Spatrick }
214bb684c34Spatrick 
addLazyArchive(StringRef name,ArchiveFile * file,const object::Archive::Symbol & sym)215*dfe94b16Srobert Symbol *SymbolTable::addLazyArchive(StringRef name, ArchiveFile *file,
2161cf9926bSpatrick                                     const object::Archive::Symbol &sym) {
217*dfe94b16Srobert   auto [s, wasInserted] = insert(name, file);
218bb684c34Spatrick 
219*dfe94b16Srobert   if (wasInserted) {
220*dfe94b16Srobert     replaceSymbol<LazyArchive>(s, file, sym);
221*dfe94b16Srobert   } else if (isa<Undefined>(s)) {
222bb684c34Spatrick     file->fetch(sym);
223*dfe94b16Srobert   } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
224*dfe94b16Srobert     if (dysym->isWeakDef()) {
225*dfe94b16Srobert       if (dysym->getRefState() != RefState::Unreferenced)
226*dfe94b16Srobert         file->fetch(sym);
227*dfe94b16Srobert       else
228*dfe94b16Srobert         replaceSymbol<LazyArchive>(s, file, sym);
229*dfe94b16Srobert     }
230*dfe94b16Srobert   }
231*dfe94b16Srobert   return s;
232*dfe94b16Srobert }
233*dfe94b16Srobert 
addLazyObject(StringRef name,InputFile & file)234*dfe94b16Srobert Symbol *SymbolTable::addLazyObject(StringRef name, InputFile &file) {
235*dfe94b16Srobert   auto [s, wasInserted] = insert(name, &file);
236*dfe94b16Srobert 
237*dfe94b16Srobert   if (wasInserted) {
238*dfe94b16Srobert     replaceSymbol<LazyObject>(s, file, name);
239*dfe94b16Srobert   } else if (isa<Undefined>(s)) {
240*dfe94b16Srobert     extract(file, name);
241*dfe94b16Srobert   } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
242*dfe94b16Srobert     if (dysym->isWeakDef()) {
243*dfe94b16Srobert       if (dysym->getRefState() != RefState::Unreferenced)
244*dfe94b16Srobert         extract(file, name);
245*dfe94b16Srobert       else
246*dfe94b16Srobert         replaceSymbol<LazyObject>(s, file, name);
247*dfe94b16Srobert     }
248*dfe94b16Srobert   }
249bb684c34Spatrick   return s;
250bb684c34Spatrick }
251bb684c34Spatrick 
addSynthetic(StringRef name,InputSection * isec,uint64_t value,bool isPrivateExtern,bool includeInSymtab,bool referencedDynamically)2521cf9926bSpatrick Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
2531cf9926bSpatrick                                    uint64_t value, bool isPrivateExtern,
2541cf9926bSpatrick                                    bool includeInSymtab,
2551cf9926bSpatrick                                    bool referencedDynamically) {
256*dfe94b16Srobert   assert(!isec || !isec->getFile()); // See makeSyntheticInputSection().
257*dfe94b16Srobert   Defined *s =
258*dfe94b16Srobert       addDefined(name, /*file=*/nullptr, isec, value, /*size=*/0,
259*dfe94b16Srobert                  /*isWeakDef=*/false, isPrivateExtern, /*isThumb=*/false,
260*dfe94b16Srobert                  referencedDynamically, /*noDeadStrip=*/false,
261*dfe94b16Srobert                  /*isWeakDefCanBeHidden=*/false);
2621cf9926bSpatrick   s->includeInSymtab = includeInSymtab;
2631cf9926bSpatrick   return s;
2641cf9926bSpatrick }
2651cf9926bSpatrick 
2661cf9926bSpatrick enum class Boundary {
2671cf9926bSpatrick   Start,
2681cf9926bSpatrick   End,
2691cf9926bSpatrick };
2701cf9926bSpatrick 
createBoundarySymbol(const Undefined & sym)2711cf9926bSpatrick static Defined *createBoundarySymbol(const Undefined &sym) {
2721cf9926bSpatrick   return symtab->addSynthetic(
2731cf9926bSpatrick       sym.getName(), /*isec=*/nullptr, /*value=*/-1, /*isPrivateExtern=*/true,
2741cf9926bSpatrick       /*includeInSymtab=*/false, /*referencedDynamically=*/false);
2751cf9926bSpatrick }
2761cf9926bSpatrick 
handleSectionBoundarySymbol(const Undefined & sym,StringRef segSect,Boundary which)2771cf9926bSpatrick static void handleSectionBoundarySymbol(const Undefined &sym, StringRef segSect,
2781cf9926bSpatrick                                         Boundary which) {
279*dfe94b16Srobert   auto [segName, sectName] = segSect.split('$');
2801cf9926bSpatrick 
2811cf9926bSpatrick   // Attach the symbol to any InputSection that will end up in the right
2821cf9926bSpatrick   // OutputSection -- it doesn't matter which one we pick.
2831cf9926bSpatrick   // Don't bother looking through inputSections for a matching
2841cf9926bSpatrick   // ConcatInputSection -- we need to create ConcatInputSection for
2851cf9926bSpatrick   // non-existing sections anyways, and that codepath works even if we should
2861cf9926bSpatrick   // already have a ConcatInputSection with the right name.
2871cf9926bSpatrick 
2881cf9926bSpatrick   OutputSection *osec = nullptr;
2891cf9926bSpatrick   // This looks for __TEXT,__cstring etc.
2901cf9926bSpatrick   for (SyntheticSection *ssec : syntheticSections)
2911cf9926bSpatrick     if (ssec->segname == segName && ssec->name == sectName) {
2921cf9926bSpatrick       osec = ssec->isec->parent;
2931cf9926bSpatrick       break;
2941cf9926bSpatrick     }
2951cf9926bSpatrick 
2961cf9926bSpatrick   if (!osec) {
297*dfe94b16Srobert     ConcatInputSection *isec = makeSyntheticInputSection(segName, sectName);
2981cf9926bSpatrick 
2991cf9926bSpatrick     // This runs after markLive() and is only called for Undefineds that are
3001cf9926bSpatrick     // live. Marking the isec live ensures an OutputSection is created that the
3011cf9926bSpatrick     // start/end symbol can refer to.
3021cf9926bSpatrick     assert(sym.isLive());
3031cf9926bSpatrick     isec->live = true;
3041cf9926bSpatrick 
3051cf9926bSpatrick     // This runs after gatherInputSections(), so need to explicitly set parent
3061cf9926bSpatrick     // and add to inputSections.
3071cf9926bSpatrick     osec = isec->parent = ConcatOutputSection::getOrCreateForInput(isec);
3081cf9926bSpatrick     inputSections.push_back(isec);
3091cf9926bSpatrick   }
3101cf9926bSpatrick 
3111cf9926bSpatrick   if (which == Boundary::Start)
3121cf9926bSpatrick     osec->sectionStartSymbols.push_back(createBoundarySymbol(sym));
3131cf9926bSpatrick   else
3141cf9926bSpatrick     osec->sectionEndSymbols.push_back(createBoundarySymbol(sym));
3151cf9926bSpatrick }
3161cf9926bSpatrick 
handleSegmentBoundarySymbol(const Undefined & sym,StringRef segName,Boundary which)3171cf9926bSpatrick static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
3181cf9926bSpatrick                                         Boundary which) {
3191cf9926bSpatrick   OutputSegment *seg = getOrCreateOutputSegment(segName);
3201cf9926bSpatrick   if (which == Boundary::Start)
3211cf9926bSpatrick     seg->segmentStartSymbols.push_back(createBoundarySymbol(sym));
3221cf9926bSpatrick   else
3231cf9926bSpatrick     seg->segmentEndSymbols.push_back(createBoundarySymbol(sym));
3241cf9926bSpatrick }
3251cf9926bSpatrick 
326*dfe94b16Srobert // Try to find a definition for an undefined symbol.
327*dfe94b16Srobert // Returns true if a definition was found and no diagnostics are needed.
recoverFromUndefinedSymbol(const Undefined & sym)328*dfe94b16Srobert static bool recoverFromUndefinedSymbol(const Undefined &sym) {
3291cf9926bSpatrick   // Handle start/end symbols.
3301cf9926bSpatrick   StringRef name = sym.getName();
331*dfe94b16Srobert   if (name.consume_front("section$start$")) {
332*dfe94b16Srobert     handleSectionBoundarySymbol(sym, name, Boundary::Start);
333*dfe94b16Srobert     return true;
334*dfe94b16Srobert   }
335*dfe94b16Srobert   if (name.consume_front("section$end$")) {
336*dfe94b16Srobert     handleSectionBoundarySymbol(sym, name, Boundary::End);
337*dfe94b16Srobert     return true;
338*dfe94b16Srobert   }
339*dfe94b16Srobert   if (name.consume_front("segment$start$")) {
340*dfe94b16Srobert     handleSegmentBoundarySymbol(sym, name, Boundary::Start);
341*dfe94b16Srobert     return true;
342*dfe94b16Srobert   }
343*dfe94b16Srobert   if (name.consume_front("segment$end$")) {
344*dfe94b16Srobert     handleSegmentBoundarySymbol(sym, name, Boundary::End);
345*dfe94b16Srobert     return true;
346*dfe94b16Srobert   }
347*dfe94b16Srobert 
348*dfe94b16Srobert   // Leave dtrace symbols, since we will handle them when we do the relocation
349*dfe94b16Srobert   if (name.startswith("___dtrace_"))
350*dfe94b16Srobert     return true;
3511cf9926bSpatrick 
3521cf9926bSpatrick   // Handle -U.
3531cf9926bSpatrick   if (config->explicitDynamicLookups.count(sym.getName())) {
3541cf9926bSpatrick     symtab->addDynamicLookup(sym.getName());
355*dfe94b16Srobert     return true;
3561cf9926bSpatrick   }
3571cf9926bSpatrick 
3581cf9926bSpatrick   // Handle -undefined.
359*dfe94b16Srobert   if (config->undefinedSymbolTreatment ==
360*dfe94b16Srobert           UndefinedSymbolTreatment::dynamic_lookup ||
361*dfe94b16Srobert       config->undefinedSymbolTreatment == UndefinedSymbolTreatment::suppress) {
362*dfe94b16Srobert     symtab->addDynamicLookup(sym.getName());
363*dfe94b16Srobert     return true;
364*dfe94b16Srobert   }
365*dfe94b16Srobert 
366*dfe94b16Srobert   // We do not return true here, as we still need to print diagnostics.
367*dfe94b16Srobert   if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::warning)
368*dfe94b16Srobert     symtab->addDynamicLookup(sym.getName());
369*dfe94b16Srobert 
370*dfe94b16Srobert   return false;
371*dfe94b16Srobert }
372*dfe94b16Srobert 
373*dfe94b16Srobert namespace {
374*dfe94b16Srobert struct UndefinedDiag {
375*dfe94b16Srobert   struct SectionAndOffset {
376*dfe94b16Srobert     const InputSection *isec;
377*dfe94b16Srobert     uint64_t offset;
378*dfe94b16Srobert   };
379*dfe94b16Srobert 
380*dfe94b16Srobert   std::vector<SectionAndOffset> codeReferences;
381*dfe94b16Srobert   std::vector<std::string> otherReferences;
382*dfe94b16Srobert };
383*dfe94b16Srobert 
384*dfe94b16Srobert MapVector<const Undefined *, UndefinedDiag> undefs;
385*dfe94b16Srobert }
386*dfe94b16Srobert 
reportPendingDuplicateSymbols()387*dfe94b16Srobert void macho::reportPendingDuplicateSymbols() {
388*dfe94b16Srobert   for (const auto &duplicate : dupSymDiags) {
389*dfe94b16Srobert     if (!config->deadStripDuplicates || duplicate.sym->isLive()) {
390*dfe94b16Srobert       std::string message =
391*dfe94b16Srobert           "duplicate symbol: " + toString(*duplicate.sym) + "\n>>> defined in ";
392*dfe94b16Srobert       if (!duplicate.src1.first.empty())
393*dfe94b16Srobert         message += duplicate.src1.first + "\n>>>            ";
394*dfe94b16Srobert       message += duplicate.src1.second + "\n>>> defined in ";
395*dfe94b16Srobert       if (!duplicate.src2.first.empty())
396*dfe94b16Srobert         message += duplicate.src2.first + "\n>>>            ";
397*dfe94b16Srobert       error(message + duplicate.src2.second);
398*dfe94b16Srobert     }
399*dfe94b16Srobert   }
400*dfe94b16Srobert }
401*dfe94b16Srobert 
402*dfe94b16Srobert // Check whether the definition name def is a mangled function name that matches
403*dfe94b16Srobert // the reference name ref.
canSuggestExternCForCXX(StringRef ref,StringRef def)404*dfe94b16Srobert static bool canSuggestExternCForCXX(StringRef ref, StringRef def) {
405*dfe94b16Srobert   llvm::ItaniumPartialDemangler d;
406*dfe94b16Srobert   std::string name = def.str();
407*dfe94b16Srobert   if (d.partialDemangle(name.c_str()))
408*dfe94b16Srobert     return false;
409*dfe94b16Srobert   char *buf = d.getFunctionName(nullptr, nullptr);
410*dfe94b16Srobert   if (!buf)
411*dfe94b16Srobert     return false;
412*dfe94b16Srobert   bool ret = ref == buf;
413*dfe94b16Srobert   free(buf);
414*dfe94b16Srobert   return ret;
415*dfe94b16Srobert }
416*dfe94b16Srobert 
417*dfe94b16Srobert // Suggest an alternative spelling of an "undefined symbol" diagnostic. Returns
418*dfe94b16Srobert // the suggested symbol, which is either in the symbol table, or in the same
419*dfe94b16Srobert // file of sym.
getAlternativeSpelling(const Undefined & sym,std::string & pre_hint,std::string & post_hint)420*dfe94b16Srobert static const Symbol *getAlternativeSpelling(const Undefined &sym,
421*dfe94b16Srobert                                             std::string &pre_hint,
422*dfe94b16Srobert                                             std::string &post_hint) {
423*dfe94b16Srobert   DenseMap<StringRef, const Symbol *> map;
424*dfe94b16Srobert   if (sym.getFile() && sym.getFile()->kind() == InputFile::ObjKind) {
425*dfe94b16Srobert     // Build a map of local defined symbols.
426*dfe94b16Srobert     for (const Symbol *s : sym.getFile()->symbols)
427*dfe94b16Srobert       if (auto *defined = dyn_cast_or_null<Defined>(s))
428*dfe94b16Srobert         if (!defined->isExternal())
429*dfe94b16Srobert           map.try_emplace(s->getName(), s);
430*dfe94b16Srobert   }
431*dfe94b16Srobert 
432*dfe94b16Srobert   auto suggest = [&](StringRef newName) -> const Symbol * {
433*dfe94b16Srobert     // If defined locally.
434*dfe94b16Srobert     if (const Symbol *s = map.lookup(newName))
435*dfe94b16Srobert       return s;
436*dfe94b16Srobert 
437*dfe94b16Srobert     // If in the symbol table and not undefined.
438*dfe94b16Srobert     if (const Symbol *s = symtab->find(newName))
439*dfe94b16Srobert       if (dyn_cast<Undefined>(s) == nullptr)
440*dfe94b16Srobert         return s;
441*dfe94b16Srobert 
442*dfe94b16Srobert     return nullptr;
443*dfe94b16Srobert   };
444*dfe94b16Srobert 
445*dfe94b16Srobert   // This loop enumerates all strings of Levenshtein distance 1 as typo
446*dfe94b16Srobert   // correction candidates and suggests the one that exists as a non-undefined
447*dfe94b16Srobert   // symbol.
448*dfe94b16Srobert   StringRef name = sym.getName();
449*dfe94b16Srobert   for (size_t i = 0, e = name.size(); i != e + 1; ++i) {
450*dfe94b16Srobert     // Insert a character before name[i].
451*dfe94b16Srobert     std::string newName = (name.substr(0, i) + "0" + name.substr(i)).str();
452*dfe94b16Srobert     for (char c = '0'; c <= 'z'; ++c) {
453*dfe94b16Srobert       newName[i] = c;
454*dfe94b16Srobert       if (const Symbol *s = suggest(newName))
455*dfe94b16Srobert         return s;
456*dfe94b16Srobert     }
457*dfe94b16Srobert     if (i == e)
458*dfe94b16Srobert       break;
459*dfe94b16Srobert 
460*dfe94b16Srobert     // Substitute name[i].
461*dfe94b16Srobert     newName = std::string(name);
462*dfe94b16Srobert     for (char c = '0'; c <= 'z'; ++c) {
463*dfe94b16Srobert       newName[i] = c;
464*dfe94b16Srobert       if (const Symbol *s = suggest(newName))
465*dfe94b16Srobert         return s;
466*dfe94b16Srobert     }
467*dfe94b16Srobert 
468*dfe94b16Srobert     // Transpose name[i] and name[i+1]. This is of edit distance 2 but it is
469*dfe94b16Srobert     // common.
470*dfe94b16Srobert     if (i + 1 < e) {
471*dfe94b16Srobert       newName[i] = name[i + 1];
472*dfe94b16Srobert       newName[i + 1] = name[i];
473*dfe94b16Srobert       if (const Symbol *s = suggest(newName))
474*dfe94b16Srobert         return s;
475*dfe94b16Srobert     }
476*dfe94b16Srobert 
477*dfe94b16Srobert     // Delete name[i].
478*dfe94b16Srobert     newName = (name.substr(0, i) + name.substr(i + 1)).str();
479*dfe94b16Srobert     if (const Symbol *s = suggest(newName))
480*dfe94b16Srobert       return s;
481*dfe94b16Srobert   }
482*dfe94b16Srobert 
483*dfe94b16Srobert   // Case mismatch, e.g. Foo vs FOO.
484*dfe94b16Srobert   for (auto &it : map)
485*dfe94b16Srobert     if (name.equals_insensitive(it.first))
486*dfe94b16Srobert       return it.second;
487*dfe94b16Srobert   for (Symbol *sym : symtab->getSymbols())
488*dfe94b16Srobert     if (dyn_cast<Undefined>(sym) == nullptr &&
489*dfe94b16Srobert         name.equals_insensitive(sym->getName()))
490*dfe94b16Srobert       return sym;
491*dfe94b16Srobert 
492*dfe94b16Srobert   // The reference may be a mangled name while the definition is not. Suggest a
493*dfe94b16Srobert   // missing extern "C".
494*dfe94b16Srobert   if (name.startswith("__Z")) {
495*dfe94b16Srobert     std::string buf = name.str();
496*dfe94b16Srobert     llvm::ItaniumPartialDemangler d;
497*dfe94b16Srobert     if (!d.partialDemangle(buf.c_str()))
498*dfe94b16Srobert       if (char *buf = d.getFunctionName(nullptr, nullptr)) {
499*dfe94b16Srobert         const Symbol *s = suggest((Twine("_") + buf).str());
500*dfe94b16Srobert         free(buf);
501*dfe94b16Srobert         if (s) {
502*dfe94b16Srobert           pre_hint = ": extern \"C\" ";
503*dfe94b16Srobert           return s;
504*dfe94b16Srobert         }
505*dfe94b16Srobert       }
506*dfe94b16Srobert   } else {
507*dfe94b16Srobert     StringRef name_without_underscore = name;
508*dfe94b16Srobert     name_without_underscore.consume_front("_");
509*dfe94b16Srobert     const Symbol *s = nullptr;
510*dfe94b16Srobert     for (auto &it : map)
511*dfe94b16Srobert       if (canSuggestExternCForCXX(name_without_underscore, it.first)) {
512*dfe94b16Srobert         s = it.second;
513*dfe94b16Srobert         break;
514*dfe94b16Srobert       }
515*dfe94b16Srobert     if (!s)
516*dfe94b16Srobert       for (Symbol *sym : symtab->getSymbols())
517*dfe94b16Srobert         if (canSuggestExternCForCXX(name_without_underscore, sym->getName())) {
518*dfe94b16Srobert           s = sym;
519*dfe94b16Srobert           break;
520*dfe94b16Srobert         }
521*dfe94b16Srobert     if (s) {
522*dfe94b16Srobert       pre_hint = " to declare ";
523*dfe94b16Srobert       post_hint = " as extern \"C\"?";
524*dfe94b16Srobert       return s;
525*dfe94b16Srobert     }
526*dfe94b16Srobert   }
527*dfe94b16Srobert 
528*dfe94b16Srobert   return nullptr;
529*dfe94b16Srobert }
530*dfe94b16Srobert 
reportUndefinedSymbol(const Undefined & sym,const UndefinedDiag & locations,bool correctSpelling)531*dfe94b16Srobert static void reportUndefinedSymbol(const Undefined &sym,
532*dfe94b16Srobert                                   const UndefinedDiag &locations,
533*dfe94b16Srobert                                   bool correctSpelling) {
5341cf9926bSpatrick   std::string message = "undefined symbol";
5351cf9926bSpatrick   if (config->archMultiple)
5361cf9926bSpatrick     message += (" for arch " + getArchitectureName(config->arch())).str();
5371cf9926bSpatrick   message += ": " + toString(sym);
538*dfe94b16Srobert 
539*dfe94b16Srobert   const size_t maxUndefinedReferences = 3;
540*dfe94b16Srobert   size_t i = 0;
541*dfe94b16Srobert   for (const std::string &loc : locations.otherReferences) {
542*dfe94b16Srobert     if (i >= maxUndefinedReferences)
5431cf9926bSpatrick       break;
544*dfe94b16Srobert     message += "\n>>> referenced by " + loc;
545*dfe94b16Srobert     ++i;
546*dfe94b16Srobert   }
547*dfe94b16Srobert 
548*dfe94b16Srobert   for (const UndefinedDiag::SectionAndOffset &loc : locations.codeReferences) {
549*dfe94b16Srobert     if (i >= maxUndefinedReferences)
5501cf9926bSpatrick       break;
551*dfe94b16Srobert     message += "\n>>> referenced by ";
552*dfe94b16Srobert     std::string src = loc.isec->getSourceLocation(loc.offset);
553*dfe94b16Srobert     if (!src.empty())
554*dfe94b16Srobert       message += src + "\n>>>               ";
555*dfe94b16Srobert     message += loc.isec->getLocation(loc.offset);
556*dfe94b16Srobert     ++i;
557*dfe94b16Srobert   }
558*dfe94b16Srobert 
559*dfe94b16Srobert   size_t totalReferences =
560*dfe94b16Srobert       locations.otherReferences.size() + locations.codeReferences.size();
561*dfe94b16Srobert   if (totalReferences > i)
562*dfe94b16Srobert     message +=
563*dfe94b16Srobert         ("\n>>> referenced " + Twine(totalReferences - i) + " more times")
564*dfe94b16Srobert             .str();
565*dfe94b16Srobert 
566*dfe94b16Srobert   if (correctSpelling) {
567*dfe94b16Srobert     std::string pre_hint = ": ", post_hint;
568*dfe94b16Srobert     if (const Symbol *corrected =
569*dfe94b16Srobert             getAlternativeSpelling(sym, pre_hint, post_hint)) {
570*dfe94b16Srobert       message +=
571*dfe94b16Srobert           "\n>>> did you mean" + pre_hint + toString(*corrected) + post_hint;
572*dfe94b16Srobert       if (corrected->getFile())
573*dfe94b16Srobert         message += "\n>>> defined in: " + toString(corrected->getFile());
5741cf9926bSpatrick     }
5751cf9926bSpatrick   }
5761cf9926bSpatrick 
577*dfe94b16Srobert   if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::error)
578*dfe94b16Srobert     error(message);
579*dfe94b16Srobert   else if (config->undefinedSymbolTreatment ==
580*dfe94b16Srobert            UndefinedSymbolTreatment::warning)
581*dfe94b16Srobert     warn(message);
582*dfe94b16Srobert   else
583*dfe94b16Srobert     assert(false && "diagnostics make sense for -undefined error|warning only");
584*dfe94b16Srobert }
585*dfe94b16Srobert 
reportPendingUndefinedSymbols()586*dfe94b16Srobert void macho::reportPendingUndefinedSymbols() {
587*dfe94b16Srobert   // Enable spell corrector for the first 2 diagnostics.
588*dfe94b16Srobert   for (const auto &[i, undef] : llvm::enumerate(undefs))
589*dfe94b16Srobert     reportUndefinedSymbol(*undef.first, undef.second, i < 2);
590*dfe94b16Srobert 
591*dfe94b16Srobert   // This function is called multiple times during execution. Clear the printed
592*dfe94b16Srobert   // diagnostics to avoid printing the same things again the next time.
593*dfe94b16Srobert   undefs.clear();
594*dfe94b16Srobert }
595*dfe94b16Srobert 
treatUndefinedSymbol(const Undefined & sym,StringRef source)596*dfe94b16Srobert void macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
597*dfe94b16Srobert   if (recoverFromUndefinedSymbol(sym))
598*dfe94b16Srobert     return;
599*dfe94b16Srobert 
600*dfe94b16Srobert   undefs[&sym].otherReferences.push_back(source.str());
601*dfe94b16Srobert }
602*dfe94b16Srobert 
treatUndefinedSymbol(const Undefined & sym,const InputSection * isec,uint64_t offset)603*dfe94b16Srobert void macho::treatUndefinedSymbol(const Undefined &sym, const InputSection *isec,
604*dfe94b16Srobert                                  uint64_t offset) {
605*dfe94b16Srobert   if (recoverFromUndefinedSymbol(sym))
606*dfe94b16Srobert     return;
607*dfe94b16Srobert 
608*dfe94b16Srobert   undefs[&sym].codeReferences.push_back({isec, offset});
609*dfe94b16Srobert }
610*dfe94b16Srobert 
611*dfe94b16Srobert std::unique_ptr<SymbolTable> macho::symtab;
612