16acd3003SFangrui Song //===- SymbolTable.cpp ----------------------------------------------------===//
26acd3003SFangrui Song //
36acd3003SFangrui Song // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46acd3003SFangrui Song // See https://llvm.org/LICENSE.txt for license information.
56acd3003SFangrui Song // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66acd3003SFangrui Song //
76acd3003SFangrui Song //===----------------------------------------------------------------------===//
86acd3003SFangrui Song
96acd3003SFangrui Song #include "SymbolTable.h"
1004e8d0b6SNico Weber #include "ConcatOutputSection.h"
11cc1cf633SGreg McGary #include "Config.h"
126acd3003SFangrui Song #include "InputFiles.h"
13002eda70SJez Ng #include "InputSection.h"
146acd3003SFangrui Song #include "Symbols.h"
1504e8d0b6SNico Weber #include "SyntheticSections.h"
166acd3003SFangrui Song #include "lld/Common/ErrorHandler.h"
176acd3003SFangrui Song #include "lld/Common/Memory.h"
186acd3003SFangrui Song
196acd3003SFangrui Song using namespace llvm;
206acd3003SFangrui Song using namespace lld;
216acd3003SFangrui Song using namespace lld::macho;
226acd3003SFangrui Song
find(CachedHashStringRef cachedName)23db1e845aSGreg McGary Symbol *SymbolTable::find(CachedHashStringRef cachedName) {
24db1e845aSGreg McGary auto it = symMap.find(cachedName);
256acd3003SFangrui Song if (it == symMap.end())
266acd3003SFangrui Song return nullptr;
276acd3003SFangrui Song return symVector[it->second];
286acd3003SFangrui Song }
296acd3003SFangrui Song
insert(StringRef name,const InputFile * file)30eb5b7d44SJez Ng std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
31eb5b7d44SJez Ng const InputFile *file) {
326acd3003SFangrui Song auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
336acd3003SFangrui Song
34eb5b7d44SJez Ng Symbol *sym;
35eb5b7d44SJez Ng if (!p.second) {
366acd3003SFangrui Song // Name already present in the symbol table.
37eb5b7d44SJez Ng sym = symVector[p.first->second];
38eb5b7d44SJez Ng } else {
396acd3003SFangrui Song // Name is a new symbol.
40eb5b7d44SJez Ng sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
416acd3003SFangrui Song symVector.push_back(sym);
42eb5b7d44SJez Ng }
43eb5b7d44SJez Ng
44eb5b7d44SJez Ng sym->isUsedInRegularObj |= !file || isa<ObjFile>(file);
45eb5b7d44SJez Ng return {sym, p.second};
466acd3003SFangrui Song }
476acd3003SFangrui Song
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)48d8283d9dSJez Ng Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
49f6ad0453SAlexander Shaposhnikov InputSection *isec, uint64_t value,
50f6ad0453SAlexander Shaposhnikov uint64_t size, bool isWeakDef,
514a12248eSNico Weber bool isPrivateExtern, bool isThumb,
529b29dae3SVy Nguyen bool isReferencedDynamically, bool noDeadStrip,
539b29dae3SVy Nguyen bool isWeakDefCanBeHidden) {
546acd3003SFangrui Song Symbol *s;
556acd3003SFangrui Song bool wasInserted;
562a38dba7SJez Ng bool overridesWeakDef = false;
57eb5b7d44SJez Ng std::tie(s, wasInserted) = insert(name, file);
586acd3003SFangrui Song
59d5a70db1SNico Weber assert(!isWeakDef || (isa<BitcodeFile>(file) && !isec) ||
60f6b6e721SJez Ng (isa<ObjFile>(file) && file == isec->getFile()));
61d5a70db1SNico Weber
6231d58858SJez Ng if (!wasInserted) {
6331d58858SJez Ng if (auto *defined = dyn_cast<Defined>(s)) {
6413f439a1SNico Weber if (isWeakDef) {
652e1be96dSVy Nguyen // See further comment in createDefined() in InputFiles.cpp
664a12248eSNico Weber if (defined->isWeakDef()) {
6713f439a1SNico Weber defined->privateExtern &= isPrivateExtern;
689b29dae3SVy Nguyen defined->weakDefCanBeHidden &= isWeakDefCanBeHidden;
694a12248eSNico Weber defined->referencedDynamically |= isReferencedDynamically;
70a5645513SNico Weber defined->noDeadStrip |= noDeadStrip;
712e1be96dSVy Nguyen }
72d5a70db1SNico Weber // FIXME: Handle this for bitcode files.
737f2ba39bSJez Ng if (auto concatIsec = dyn_cast_or_null<ConcatInputSection>(isec))
747f2ba39bSJez Ng concatIsec->wasCoalesced = true;
75eb4a5178SVy Nguyen return defined;
76b2d92584SVy Nguyen }
772e1be96dSVy Nguyen
782e1be96dSVy Nguyen if (defined->isWeakDef()) {
792e1be96dSVy Nguyen // FIXME: Handle this for bitcode files.
802e1be96dSVy Nguyen if (auto concatIsec =
812e1be96dSVy Nguyen dyn_cast_or_null<ConcatInputSection>(defined->isec)) {
822e1be96dSVy Nguyen concatIsec->wasCoalesced = true;
832e1be96dSVy Nguyen concatIsec->symbols.erase(llvm::find(concatIsec->symbols, defined));
842e1be96dSVy Nguyen }
852e1be96dSVy Nguyen } else {
86ed39fd51SDaniel Bertalan std::string src1 = defined->getSourceLocation();
87ed39fd51SDaniel Bertalan std::string src2 = isec ? isec->getSourceLocation(value) : "";
88ed39fd51SDaniel Bertalan
89ed39fd51SDaniel Bertalan std::string message =
90ed39fd51SDaniel Bertalan "duplicate symbol: " + toString(*defined) + "\n>>> defined in ";
91ed39fd51SDaniel Bertalan if (!src1.empty())
92ed39fd51SDaniel Bertalan message += src1 + "\n>>> ";
93ed39fd51SDaniel Bertalan message += toString(defined->getFile()) + "\n>>> defined in ";
94ed39fd51SDaniel Bertalan if (!src2.empty())
95ed39fd51SDaniel Bertalan message += src2 + "\n>>> ";
96ed39fd51SDaniel Bertalan error(message + toString(file));
972e1be96dSVy Nguyen }
982e1be96dSVy Nguyen
992a38dba7SJez Ng } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
1002a38dba7SJez Ng overridesWeakDef = !isWeakDef && dysym->isWeakDef();
1012c190341SNico Weber dysym->unreference();
10231d58858SJez Ng }
10331d58858SJez Ng // Defined symbols take priority over other types of symbols, so in case
10431d58858SJez Ng // of a name conflict, we fall through to the replaceSymbol() call below.
10531d58858SJez Ng }
1066acd3003SFangrui Song
107ceff23c6SJez Ng // With -flat_namespace, all extern symbols in dylibs are interposable.
108ceff23c6SJez Ng // FIXME: Add support for `-interposable` (PR53680).
109ceff23c6SJez Ng bool interposable = config->namespaceKind == NamespaceKind::flat &&
110ceff23c6SJez Ng config->outputType != MachO::MH_EXECUTE &&
111ceff23c6SJez Ng !isPrivateExtern;
1124a12248eSNico Weber Defined *defined = replaceSymbol<Defined>(
1134a12248eSNico Weber s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
1141cff723fSJez Ng isPrivateExtern, /*includeInSymtab=*/true, isThumb,
1151cff723fSJez Ng isReferencedDynamically, noDeadStrip, overridesWeakDef,
1161cff723fSJez Ng isWeakDefCanBeHidden, interposable);
117d8283d9dSJez Ng return defined;
1186acd3003SFangrui Song }
1196acd3003SFangrui Song
aliasDefined(Defined * src,StringRef target)120*0bc10098SKeith Smiley Defined *SymbolTable::aliasDefined(Defined *src, StringRef target) {
121*0bc10098SKeith Smiley return addDefined(target, src->getFile(), src->isec, src->value, src->size,
122*0bc10098SKeith Smiley src->isWeakDef(), src->privateExtern, src->thumb,
123*0bc10098SKeith Smiley src->referencedDynamically, src->noDeadStrip,
124*0bc10098SKeith Smiley src->weakDefCanBeHidden);
125*0bc10098SKeith Smiley }
126*0bc10098SKeith Smiley
addUndefined(StringRef name,InputFile * file,bool isWeakRef)127163dcd85SJez Ng Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file,
128163dcd85SJez Ng bool isWeakRef) {
1296acd3003SFangrui Song Symbol *s;
1306acd3003SFangrui Song bool wasInserted;
131eb5b7d44SJez Ng std::tie(s, wasInserted) = insert(name, file);
1326acd3003SFangrui Song
133fdc0c219SGreg McGary RefState refState = isWeakRef ? RefState::Weak : RefState::Strong;
134811444d7SJez Ng
1356acd3003SFangrui Song if (wasInserted)
136163dcd85SJez Ng replaceSymbol<Undefined>(s, name, file, refState);
13797a5dccbSFangrui Song else if (auto *lazy = dyn_cast<LazyArchive>(s))
1382b920ae7SKellie Medlin lazy->fetchArchiveMember();
1390aae2bf3SFangrui Song else if (isa<LazyObject>(s))
1400aae2bf3SFangrui Song extract(*s->getFile(), s->getName());
141811444d7SJez Ng else if (auto *dynsym = dyn_cast<DylibSymbol>(s))
1422c190341SNico Weber dynsym->reference(refState);
143811444d7SJez Ng else if (auto *undefined = dyn_cast<Undefined>(s))
144811444d7SJez Ng undefined->refState = std::max(undefined->refState, refState);
1456acd3003SFangrui Song return s;
1466acd3003SFangrui Song }
1476acd3003SFangrui Song
addCommon(StringRef name,InputFile * file,uint64_t size,uint32_t align,bool isPrivateExtern)148c32e69b2SJez Ng Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size,
14913f439a1SNico Weber uint32_t align, bool isPrivateExtern) {
150c32e69b2SJez Ng Symbol *s;
151c32e69b2SJez Ng bool wasInserted;
152eb5b7d44SJez Ng std::tie(s, wasInserted) = insert(name, file);
153c32e69b2SJez Ng
154c32e69b2SJez Ng if (!wasInserted) {
155c32e69b2SJez Ng if (auto *common = dyn_cast<CommonSymbol>(s)) {
156c32e69b2SJez Ng if (size < common->size)
157c32e69b2SJez Ng return s;
1585213576fSJez Ng } else if (isa<Defined>(s)) {
159c32e69b2SJez Ng return s;
160c32e69b2SJez Ng }
1615213576fSJez Ng // Common symbols take priority over all non-Defined symbols, so in case of
1625213576fSJez Ng // a name conflict, we fall through to the replaceSymbol() call below.
163c32e69b2SJez Ng }
164c32e69b2SJez Ng
16513f439a1SNico Weber replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern);
166c32e69b2SJez Ng return s;
167c32e69b2SJez Ng }
168c32e69b2SJez Ng
addDylib(StringRef name,DylibFile * file,bool isWeakDef,bool isTlv)1693c9100fbSJez Ng Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef,
1703c9100fbSJez Ng bool isTlv) {
171060efd24SJez Ng Symbol *s;
172060efd24SJez Ng bool wasInserted;
173eb5b7d44SJez Ng std::tie(s, wasInserted) = insert(name, file);
174060efd24SJez Ng
175fdc0c219SGreg McGary RefState refState = RefState::Unreferenced;
176811444d7SJez Ng if (!wasInserted) {
177811444d7SJez Ng if (auto *defined = dyn_cast<Defined>(s)) {
178811444d7SJez Ng if (isWeakDef && !defined->isWeakDef())
1792a38dba7SJez Ng defined->overridesWeakDef = true;
180811444d7SJez Ng } else if (auto *undefined = dyn_cast<Undefined>(s)) {
181811444d7SJez Ng refState = undefined->refState;
182811444d7SJez Ng } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
1832c190341SNico Weber refState = dysym->getRefState();
184811444d7SJez Ng }
185811444d7SJez Ng }
1862a38dba7SJez Ng
187cafb6cd1SNico Weber bool isDynamicLookup = file == nullptr;
18831d58858SJez Ng if (wasInserted || isa<Undefined>(s) ||
189cafb6cd1SNico Weber (isa<DylibSymbol>(s) &&
190cafb6cd1SNico Weber ((!isWeakDef && s->isWeakDef()) ||
1912c190341SNico Weber (!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) {
1922c190341SNico Weber if (auto *dynsym = dyn_cast<DylibSymbol>(s))
1932c190341SNico Weber dynsym->unreference();
194811444d7SJez Ng replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv);
1952c190341SNico Weber }
19631d58858SJez Ng
197060efd24SJez Ng return s;
198060efd24SJez Ng }
199060efd24SJez Ng
addDynamicLookup(StringRef name)200cafb6cd1SNico Weber Symbol *SymbolTable::addDynamicLookup(StringRef name) {
201cafb6cd1SNico Weber return addDylib(name, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false);
202cafb6cd1SNico Weber }
203cafb6cd1SNico Weber
addLazyArchive(StringRef name,ArchiveFile * file,const object::Archive::Symbol & sym)20497a5dccbSFangrui Song Symbol *SymbolTable::addLazyArchive(StringRef name, ArchiveFile *file,
205e98b441aSJez Ng const object::Archive::Symbol &sym) {
2062b920ae7SKellie Medlin Symbol *s;
2072b920ae7SKellie Medlin bool wasInserted;
208eb5b7d44SJez Ng std::tie(s, wasInserted) = insert(name, file);
2092b920ae7SKellie Medlin
2101b443647SJez Ng if (wasInserted) {
21197a5dccbSFangrui Song replaceSymbol<LazyArchive>(s, file, sym);
2121b443647SJez Ng } else if (isa<Undefined>(s)) {
2132b920ae7SKellie Medlin file->fetch(sym);
2141b443647SJez Ng } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
2151b443647SJez Ng if (dysym->isWeakDef()) {
2161b443647SJez Ng if (dysym->getRefState() != RefState::Unreferenced)
2171b443647SJez Ng file->fetch(sym);
2181b443647SJez Ng else
21997a5dccbSFangrui Song replaceSymbol<LazyArchive>(s, file, sym);
2201b443647SJez Ng }
2211b443647SJez Ng }
2222b920ae7SKellie Medlin return s;
2232b920ae7SKellie Medlin }
2242b920ae7SKellie Medlin
addLazyObject(StringRef name,InputFile & file)2250aae2bf3SFangrui Song Symbol *SymbolTable::addLazyObject(StringRef name, InputFile &file) {
2260aae2bf3SFangrui Song Symbol *s;
2270aae2bf3SFangrui Song bool wasInserted;
2280aae2bf3SFangrui Song std::tie(s, wasInserted) = insert(name, &file);
2290aae2bf3SFangrui Song
2300aae2bf3SFangrui Song if (wasInserted) {
2310aae2bf3SFangrui Song replaceSymbol<LazyObject>(s, file, name);
2320aae2bf3SFangrui Song } else if (isa<Undefined>(s)) {
2330aae2bf3SFangrui Song extract(file, name);
2340aae2bf3SFangrui Song } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
2350aae2bf3SFangrui Song if (dysym->isWeakDef()) {
2360aae2bf3SFangrui Song if (dysym->getRefState() != RefState::Unreferenced)
2370aae2bf3SFangrui Song extract(file, name);
2380aae2bf3SFangrui Song else
2390aae2bf3SFangrui Song replaceSymbol<LazyObject>(s, file, name);
2400aae2bf3SFangrui Song }
2410aae2bf3SFangrui Song }
2420aae2bf3SFangrui Song return s;
2430aae2bf3SFangrui Song }
2440aae2bf3SFangrui Song
addSynthetic(StringRef name,InputSection * isec,uint64_t value,bool isPrivateExtern,bool includeInSymtab,bool referencedDynamically)245d8283d9dSJez Ng Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
2462461804bSJez Ng uint64_t value, bool isPrivateExtern,
2474a12248eSNico Weber bool includeInSymtab,
2484a12248eSNico Weber bool referencedDynamically) {
2492cb3d28bSNico Weber assert(!isec || !isec->getFile()); // See makeSyntheticInputSection().
2509b29dae3SVy Nguyen Defined *s =
2512cb3d28bSNico Weber addDefined(name, /*file=*/nullptr, isec, value, /*size=*/0,
2521cff723fSJez Ng /*isWeakDef=*/false, isPrivateExtern, /*isThumb=*/false,
2531cff723fSJez Ng referencedDynamically, /*noDeadStrip=*/false,
2541cff723fSJez Ng /*isWeakDefCanBeHidden=*/false);
25566f34005SVy Nguyen s->includeInSymtab = includeInSymtab;
2563587de22SJez Ng return s;
2573587de22SJez Ng }
2583587de22SJez Ng
25904e8d0b6SNico Weber enum class Boundary {
26004e8d0b6SNico Weber Start,
26104e8d0b6SNico Weber End,
26204e8d0b6SNico Weber };
26304e8d0b6SNico Weber
createBoundarySymbol(const Undefined & sym)26480caa1ebSNico Weber static Defined *createBoundarySymbol(const Undefined &sym) {
26580caa1ebSNico Weber return symtab->addSynthetic(
26680caa1ebSNico Weber sym.getName(), /*isec=*/nullptr, /*value=*/-1, /*isPrivateExtern=*/true,
26780caa1ebSNico Weber /*includeInSymtab=*/false, /*referencedDynamically=*/false);
26880caa1ebSNico Weber }
26980caa1ebSNico Weber
handleSectionBoundarySymbol(const Undefined & sym,StringRef segSect,Boundary which)27004e8d0b6SNico Weber static void handleSectionBoundarySymbol(const Undefined &sym, StringRef segSect,
27104e8d0b6SNico Weber Boundary which) {
27204e8d0b6SNico Weber StringRef segName, sectName;
27304e8d0b6SNico Weber std::tie(segName, sectName) = segSect.split('$');
27404e8d0b6SNico Weber
27504e8d0b6SNico Weber // Attach the symbol to any InputSection that will end up in the right
27604e8d0b6SNico Weber // OutputSection -- it doesn't matter which one we pick.
27704e8d0b6SNico Weber // Don't bother looking through inputSections for a matching
27804e8d0b6SNico Weber // ConcatInputSection -- we need to create ConcatInputSection for
27904e8d0b6SNico Weber // non-existing sections anyways, and that codepath works even if we should
28004e8d0b6SNico Weber // already have a ConcatInputSection with the right name.
28104e8d0b6SNico Weber
28204e8d0b6SNico Weber OutputSection *osec = nullptr;
28304e8d0b6SNico Weber // This looks for __TEXT,__cstring etc.
28404e8d0b6SNico Weber for (SyntheticSection *ssec : syntheticSections)
28504e8d0b6SNico Weber if (ssec->segname == segName && ssec->name == sectName) {
28604e8d0b6SNico Weber osec = ssec->isec->parent;
28704e8d0b6SNico Weber break;
28804e8d0b6SNico Weber }
28904e8d0b6SNico Weber
29004e8d0b6SNico Weber if (!osec) {
2912b78ef06SJez Ng ConcatInputSection *isec = makeSyntheticInputSection(segName, sectName);
29204e8d0b6SNico Weber
29304e8d0b6SNico Weber // This runs after markLive() and is only called for Undefineds that are
29404e8d0b6SNico Weber // live. Marking the isec live ensures an OutputSection is created that the
29504e8d0b6SNico Weber // start/end symbol can refer to.
29604e8d0b6SNico Weber assert(sym.isLive());
29704e8d0b6SNico Weber isec->live = true;
29804e8d0b6SNico Weber
29904e8d0b6SNico Weber // This runs after gatherInputSections(), so need to explicitly set parent
30004e8d0b6SNico Weber // and add to inputSections.
30104e8d0b6SNico Weber osec = isec->parent = ConcatOutputSection::getOrCreateForInput(isec);
30204e8d0b6SNico Weber inputSections.push_back(isec);
30304e8d0b6SNico Weber }
30404e8d0b6SNico Weber
30504e8d0b6SNico Weber if (which == Boundary::Start)
30680caa1ebSNico Weber osec->sectionStartSymbols.push_back(createBoundarySymbol(sym));
30704e8d0b6SNico Weber else
30880caa1ebSNico Weber osec->sectionEndSymbols.push_back(createBoundarySymbol(sym));
30904e8d0b6SNico Weber }
31004e8d0b6SNico Weber
handleSegmentBoundarySymbol(const Undefined & sym,StringRef segName,Boundary which)31104e8d0b6SNico Weber static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
31204e8d0b6SNico Weber Boundary which) {
31380caa1ebSNico Weber OutputSegment *seg = getOrCreateOutputSegment(segName);
31480caa1ebSNico Weber if (which == Boundary::Start)
31580caa1ebSNico Weber seg->segmentStartSymbols.push_back(createBoundarySymbol(sym));
31680caa1ebSNico Weber else
31780caa1ebSNico Weber seg->segmentEndSymbols.push_back(createBoundarySymbol(sym));
31804e8d0b6SNico Weber }
31904e8d0b6SNico Weber
320f2e92cf6SDaniel Bertalan // Try to find a definition for an undefined symbol.
321f2e92cf6SDaniel Bertalan // Returns true if a definition was found and no diagnostics are needed.
recoverFromUndefinedSymbol(const Undefined & sym)322f2e92cf6SDaniel Bertalan static bool recoverFromUndefinedSymbol(const Undefined &sym) {
32304e8d0b6SNico Weber // Handle start/end symbols.
32404e8d0b6SNico Weber StringRef name = sym.getName();
325f2e92cf6SDaniel Bertalan if (name.consume_front("section$start$")) {
326f2e92cf6SDaniel Bertalan handleSectionBoundarySymbol(sym, name, Boundary::Start);
327f2e92cf6SDaniel Bertalan return true;
328f2e92cf6SDaniel Bertalan }
329f2e92cf6SDaniel Bertalan if (name.consume_front("section$end$")) {
330f2e92cf6SDaniel Bertalan handleSectionBoundarySymbol(sym, name, Boundary::End);
331f2e92cf6SDaniel Bertalan return true;
332f2e92cf6SDaniel Bertalan }
333f2e92cf6SDaniel Bertalan if (name.consume_front("segment$start$")) {
334f2e92cf6SDaniel Bertalan handleSegmentBoundarySymbol(sym, name, Boundary::Start);
335f2e92cf6SDaniel Bertalan return true;
336f2e92cf6SDaniel Bertalan }
337f2e92cf6SDaniel Bertalan if (name.consume_front("segment$end$")) {
338f2e92cf6SDaniel Bertalan handleSegmentBoundarySymbol(sym, name, Boundary::End);
339f2e92cf6SDaniel Bertalan return true;
340f2e92cf6SDaniel Bertalan }
34104e8d0b6SNico Weber
3426c641d0dSKaining Zhong // Leave dtrace symbols, since we will handle them when we do the relocation
3436c641d0dSKaining Zhong if (name.startswith("___dtrace_"))
3446c641d0dSKaining Zhong return true;
3456c641d0dSKaining Zhong
3462d6fb62eSNico Weber // Handle -U.
3472d6fb62eSNico Weber if (config->explicitDynamicLookups.count(sym.getName())) {
3482d6fb62eSNico Weber symtab->addDynamicLookup(sym.getName());
349f2e92cf6SDaniel Bertalan return true;
3502d6fb62eSNico Weber }
3512d6fb62eSNico Weber
3522d6fb62eSNico Weber // Handle -undefined.
353f2e92cf6SDaniel Bertalan if (config->undefinedSymbolTreatment ==
354f2e92cf6SDaniel Bertalan UndefinedSymbolTreatment::dynamic_lookup ||
355f2e92cf6SDaniel Bertalan config->undefinedSymbolTreatment == UndefinedSymbolTreatment::suppress) {
356f2e92cf6SDaniel Bertalan symtab->addDynamicLookup(sym.getName());
357f2e92cf6SDaniel Bertalan return true;
358f2e92cf6SDaniel Bertalan }
359f2e92cf6SDaniel Bertalan
360f2e92cf6SDaniel Bertalan // We do not return true here, as we still need to print diagnostics.
361f2e92cf6SDaniel Bertalan if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::warning)
362f2e92cf6SDaniel Bertalan symtab->addDynamicLookup(sym.getName());
363f2e92cf6SDaniel Bertalan
364f2e92cf6SDaniel Bertalan return false;
365f2e92cf6SDaniel Bertalan }
366f2e92cf6SDaniel Bertalan
3670eec7e2aSDaniel Bertalan namespace {
3680eec7e2aSDaniel Bertalan struct UndefinedDiag {
3690eec7e2aSDaniel Bertalan struct SectionAndOffset {
3700eec7e2aSDaniel Bertalan const InputSection *isec;
3710eec7e2aSDaniel Bertalan uint64_t offset;
3720eec7e2aSDaniel Bertalan };
3730eec7e2aSDaniel Bertalan
3740eec7e2aSDaniel Bertalan std::vector<SectionAndOffset> codeReferences;
3750eec7e2aSDaniel Bertalan std::vector<std::string> otherReferences;
3760eec7e2aSDaniel Bertalan };
3770eec7e2aSDaniel Bertalan
3780eec7e2aSDaniel Bertalan MapVector<const Undefined *, UndefinedDiag> undefs;
3790eec7e2aSDaniel Bertalan }
3800eec7e2aSDaniel Bertalan
reportPendingUndefinedSymbols()3810eec7e2aSDaniel Bertalan void macho::reportPendingUndefinedSymbols() {
3820eec7e2aSDaniel Bertalan for (const auto &undef : undefs) {
3830eec7e2aSDaniel Bertalan const UndefinedDiag &locations = undef.second;
3840eec7e2aSDaniel Bertalan
38564be5b7dSNico Weber std::string message = "undefined symbol";
38664be5b7dSNico Weber if (config->archMultiple)
38764be5b7dSNico Weber message += (" for arch " + getArchitectureName(config->arch())).str();
3880eec7e2aSDaniel Bertalan message += ": " + toString(*undef.first);
3890eec7e2aSDaniel Bertalan
3900eec7e2aSDaniel Bertalan const size_t maxUndefinedReferences = 3;
3910eec7e2aSDaniel Bertalan size_t i = 0;
3920eec7e2aSDaniel Bertalan for (const std::string &loc : locations.otherReferences) {
3930eec7e2aSDaniel Bertalan if (i >= maxUndefinedReferences)
3940eec7e2aSDaniel Bertalan break;
3950eec7e2aSDaniel Bertalan message += "\n>>> referenced by " + loc;
3960eec7e2aSDaniel Bertalan ++i;
3970eec7e2aSDaniel Bertalan }
3980eec7e2aSDaniel Bertalan
3990eec7e2aSDaniel Bertalan for (const UndefinedDiag::SectionAndOffset &loc :
4000eec7e2aSDaniel Bertalan locations.codeReferences) {
4010eec7e2aSDaniel Bertalan if (i >= maxUndefinedReferences)
4020eec7e2aSDaniel Bertalan break;
4035792797cSDaniel Bertalan message += "\n>>> referenced by ";
4045792797cSDaniel Bertalan std::string src = loc.isec->getSourceLocation(loc.offset);
4055792797cSDaniel Bertalan if (!src.empty())
4065792797cSDaniel Bertalan message += src + "\n>>> ";
4075792797cSDaniel Bertalan message += loc.isec->getLocation(loc.offset);
4080eec7e2aSDaniel Bertalan ++i;
4090eec7e2aSDaniel Bertalan }
4100eec7e2aSDaniel Bertalan
4110eec7e2aSDaniel Bertalan size_t totalReferences =
4120eec7e2aSDaniel Bertalan locations.otherReferences.size() + locations.codeReferences.size();
4130eec7e2aSDaniel Bertalan if (totalReferences > i)
4140eec7e2aSDaniel Bertalan message +=
4150eec7e2aSDaniel Bertalan ("\n>>> referenced " + Twine(totalReferences - i) + " more times")
4160eec7e2aSDaniel Bertalan .str();
417f2e92cf6SDaniel Bertalan
418f2e92cf6SDaniel Bertalan if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::error)
419f2e92cf6SDaniel Bertalan error(message);
420f2e92cf6SDaniel Bertalan else if (config->undefinedSymbolTreatment ==
421f2e92cf6SDaniel Bertalan UndefinedSymbolTreatment::warning)
422f2e92cf6SDaniel Bertalan warn(message);
4232516b0b5SJez Ng else
4240eec7e2aSDaniel Bertalan assert(false &&
4250eec7e2aSDaniel Bertalan "diagnostics make sense for -undefined error|warning only");
426cc1cf633SGreg McGary }
427f2e92cf6SDaniel Bertalan
4280eec7e2aSDaniel Bertalan // This function is called multiple times during execution. Clear the printed
4290eec7e2aSDaniel Bertalan // diagnostics to avoid printing the same things again the next time.
4300eec7e2aSDaniel Bertalan undefs.clear();
4310eec7e2aSDaniel Bertalan }
4320eec7e2aSDaniel Bertalan
treatUndefinedSymbol(const Undefined & sym,StringRef source)4330eec7e2aSDaniel Bertalan void macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
434f2e92cf6SDaniel Bertalan if (recoverFromUndefinedSymbol(sym))
435f2e92cf6SDaniel Bertalan return;
4360eec7e2aSDaniel Bertalan
4370eec7e2aSDaniel Bertalan undefs[&sym].otherReferences.push_back(source.str());
438f2e92cf6SDaniel Bertalan }
439f2e92cf6SDaniel Bertalan
treatUndefinedSymbol(const Undefined & sym,const InputSection * isec,uint64_t offset)4400eec7e2aSDaniel Bertalan void macho::treatUndefinedSymbol(const Undefined &sym, const InputSection *isec,
441f2e92cf6SDaniel Bertalan uint64_t offset) {
442f2e92cf6SDaniel Bertalan if (recoverFromUndefinedSymbol(sym))
443f2e92cf6SDaniel Bertalan return;
444f2e92cf6SDaniel Bertalan
4450eec7e2aSDaniel Bertalan undefs[&sym].codeReferences.push_back({isec, offset});
446cc1cf633SGreg McGary }
447cc1cf633SGreg McGary
448477bc36dSFangrui Song std::unique_ptr<SymbolTable> macho::symtab;
449