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