xref: /freebsd-src/contrib/llvm-project/lld/MachO/SymbolTable.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
15ffd83dbSDimitry Andric //===- SymbolTable.cpp ----------------------------------------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
95ffd83dbSDimitry Andric #include "SymbolTable.h"
10fe6060f1SDimitry Andric #include "ConcatOutputSection.h"
11e8d8bef9SDimitry Andric #include "Config.h"
125ffd83dbSDimitry Andric #include "InputFiles.h"
13*349cc55cSDimitry Andric #include "InputSection.h"
145ffd83dbSDimitry Andric #include "Symbols.h"
15fe6060f1SDimitry Andric #include "SyntheticSections.h"
165ffd83dbSDimitry Andric #include "lld/Common/ErrorHandler.h"
175ffd83dbSDimitry Andric #include "lld/Common/Memory.h"
185ffd83dbSDimitry Andric 
195ffd83dbSDimitry Andric using namespace llvm;
205ffd83dbSDimitry Andric using namespace lld;
215ffd83dbSDimitry Andric using namespace lld::macho;
225ffd83dbSDimitry Andric 
23fe6060f1SDimitry Andric Symbol *SymbolTable::find(CachedHashStringRef cachedName) {
24fe6060f1SDimitry Andric   auto it = symMap.find(cachedName);
255ffd83dbSDimitry Andric   if (it == symMap.end())
265ffd83dbSDimitry Andric     return nullptr;
275ffd83dbSDimitry Andric   return symVector[it->second];
285ffd83dbSDimitry Andric }
295ffd83dbSDimitry Andric 
30fe6060f1SDimitry Andric std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
31fe6060f1SDimitry Andric                                               const InputFile *file) {
325ffd83dbSDimitry Andric   auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
335ffd83dbSDimitry Andric 
34fe6060f1SDimitry Andric   Symbol *sym;
35fe6060f1SDimitry Andric   if (!p.second) {
365ffd83dbSDimitry Andric     // Name already present in the symbol table.
37fe6060f1SDimitry Andric     sym = symVector[p.first->second];
38fe6060f1SDimitry Andric   } else {
395ffd83dbSDimitry Andric     // Name is a new symbol.
40fe6060f1SDimitry Andric     sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
415ffd83dbSDimitry Andric     symVector.push_back(sym);
425ffd83dbSDimitry Andric   }
435ffd83dbSDimitry Andric 
44fe6060f1SDimitry Andric   sym->isUsedInRegularObj |= !file || isa<ObjFile>(file);
45fe6060f1SDimitry Andric   return {sym, p.second};
46fe6060f1SDimitry Andric }
47fe6060f1SDimitry Andric 
48fe6060f1SDimitry Andric Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
49fe6060f1SDimitry Andric                                  InputSection *isec, uint64_t value,
50fe6060f1SDimitry Andric                                  uint64_t size, bool isWeakDef,
51fe6060f1SDimitry Andric                                  bool isPrivateExtern, bool isThumb,
52*349cc55cSDimitry Andric                                  bool isReferencedDynamically, bool noDeadStrip,
53*349cc55cSDimitry Andric                                  bool isWeakDefCanBeHidden) {
545ffd83dbSDimitry Andric   Symbol *s;
555ffd83dbSDimitry Andric   bool wasInserted;
56e8d8bef9SDimitry Andric   bool overridesWeakDef = false;
57fe6060f1SDimitry Andric   std::tie(s, wasInserted) = insert(name, file);
58fe6060f1SDimitry Andric 
59fe6060f1SDimitry Andric   assert(!isWeakDef || (isa<BitcodeFile>(file) && !isec) ||
60fe6060f1SDimitry Andric          (isa<ObjFile>(file) && file == isec->getFile()));
615ffd83dbSDimitry Andric 
62e8d8bef9SDimitry Andric   if (!wasInserted) {
63e8d8bef9SDimitry Andric     if (auto *defined = dyn_cast<Defined>(s)) {
64e8d8bef9SDimitry Andric       if (isWeakDef) {
65*349cc55cSDimitry Andric         // See further comment in createDefined() in InputFiles.cpp
66fe6060f1SDimitry Andric         if (defined->isWeakDef()) {
67e8d8bef9SDimitry Andric           defined->privateExtern &= isPrivateExtern;
68*349cc55cSDimitry Andric           defined->weakDefCanBeHidden &= isWeakDefCanBeHidden;
69fe6060f1SDimitry Andric           defined->referencedDynamically |= isReferencedDynamically;
70fe6060f1SDimitry Andric           defined->noDeadStrip |= noDeadStrip;
71*349cc55cSDimitry Andric         }
72fe6060f1SDimitry Andric         // FIXME: Handle this for bitcode files.
73fe6060f1SDimitry Andric         if (auto concatIsec = dyn_cast_or_null<ConcatInputSection>(isec))
74fe6060f1SDimitry Andric           concatIsec->wasCoalesced = true;
75fe6060f1SDimitry Andric         return defined;
76e8d8bef9SDimitry Andric       }
77*349cc55cSDimitry Andric 
78*349cc55cSDimitry Andric       if (defined->isWeakDef()) {
79*349cc55cSDimitry Andric         // FIXME: Handle this for bitcode files.
80*349cc55cSDimitry Andric         if (auto concatIsec =
81*349cc55cSDimitry Andric                 dyn_cast_or_null<ConcatInputSection>(defined->isec)) {
82*349cc55cSDimitry Andric           concatIsec->wasCoalesced = true;
83*349cc55cSDimitry Andric           concatIsec->symbols.erase(llvm::find(concatIsec->symbols, defined));
84*349cc55cSDimitry Andric         }
85*349cc55cSDimitry Andric       } else {
86fe6060f1SDimitry Andric         error("duplicate symbol: " + name + "\n>>> defined in " +
87fe6060f1SDimitry Andric               toString(defined->getFile()) + "\n>>> defined in " +
88fe6060f1SDimitry Andric               toString(file));
89*349cc55cSDimitry Andric       }
90*349cc55cSDimitry Andric 
91e8d8bef9SDimitry Andric     } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
92e8d8bef9SDimitry Andric       overridesWeakDef = !isWeakDef && dysym->isWeakDef();
93fe6060f1SDimitry Andric       dysym->unreference();
94e8d8bef9SDimitry Andric     }
95e8d8bef9SDimitry Andric     // Defined symbols take priority over other types of symbols, so in case
96e8d8bef9SDimitry Andric     // of a name conflict, we fall through to the replaceSymbol() call below.
97e8d8bef9SDimitry Andric   }
985ffd83dbSDimitry Andric 
99fe6060f1SDimitry Andric   Defined *defined = replaceSymbol<Defined>(
100fe6060f1SDimitry Andric       s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
101*349cc55cSDimitry Andric       isPrivateExtern, isThumb, isReferencedDynamically, noDeadStrip,
102*349cc55cSDimitry Andric       overridesWeakDef, isWeakDefCanBeHidden);
103fe6060f1SDimitry Andric   return defined;
1045ffd83dbSDimitry Andric }
1055ffd83dbSDimitry Andric 
106fe6060f1SDimitry Andric Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file,
107fe6060f1SDimitry Andric                                   bool isWeakRef) {
1085ffd83dbSDimitry Andric   Symbol *s;
1095ffd83dbSDimitry Andric   bool wasInserted;
110fe6060f1SDimitry Andric   std::tie(s, wasInserted) = insert(name, file);
1115ffd83dbSDimitry Andric 
112fe6060f1SDimitry Andric   RefState refState = isWeakRef ? RefState::Weak : RefState::Strong;
113e8d8bef9SDimitry Andric 
1145ffd83dbSDimitry Andric   if (wasInserted)
115fe6060f1SDimitry Andric     replaceSymbol<Undefined>(s, name, file, refState);
116e8d8bef9SDimitry Andric   else if (auto *lazy = dyn_cast<LazySymbol>(s))
1175ffd83dbSDimitry Andric     lazy->fetchArchiveMember();
118e8d8bef9SDimitry Andric   else if (auto *dynsym = dyn_cast<DylibSymbol>(s))
119fe6060f1SDimitry Andric     dynsym->reference(refState);
120e8d8bef9SDimitry Andric   else if (auto *undefined = dyn_cast<Undefined>(s))
121e8d8bef9SDimitry Andric     undefined->refState = std::max(undefined->refState, refState);
1225ffd83dbSDimitry Andric   return s;
1235ffd83dbSDimitry Andric }
1245ffd83dbSDimitry Andric 
125e8d8bef9SDimitry Andric Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size,
126e8d8bef9SDimitry Andric                                uint32_t align, bool isPrivateExtern) {
1275ffd83dbSDimitry Andric   Symbol *s;
1285ffd83dbSDimitry Andric   bool wasInserted;
129fe6060f1SDimitry Andric   std::tie(s, wasInserted) = insert(name, file);
1305ffd83dbSDimitry Andric 
131e8d8bef9SDimitry Andric   if (!wasInserted) {
132e8d8bef9SDimitry Andric     if (auto *common = dyn_cast<CommonSymbol>(s)) {
133e8d8bef9SDimitry Andric       if (size < common->size)
134e8d8bef9SDimitry Andric         return s;
135e8d8bef9SDimitry Andric     } else if (isa<Defined>(s)) {
136e8d8bef9SDimitry Andric       return s;
137e8d8bef9SDimitry Andric     }
138e8d8bef9SDimitry Andric     // Common symbols take priority over all non-Defined symbols, so in case of
139e8d8bef9SDimitry Andric     // a name conflict, we fall through to the replaceSymbol() call below.
140e8d8bef9SDimitry Andric   }
141e8d8bef9SDimitry Andric 
142e8d8bef9SDimitry Andric   replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern);
143e8d8bef9SDimitry Andric   return s;
144e8d8bef9SDimitry Andric }
145e8d8bef9SDimitry Andric 
146e8d8bef9SDimitry Andric Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef,
147e8d8bef9SDimitry Andric                               bool isTlv) {
148e8d8bef9SDimitry Andric   Symbol *s;
149e8d8bef9SDimitry Andric   bool wasInserted;
150fe6060f1SDimitry Andric   std::tie(s, wasInserted) = insert(name, file);
151e8d8bef9SDimitry Andric 
152fe6060f1SDimitry Andric   RefState refState = RefState::Unreferenced;
153e8d8bef9SDimitry Andric   if (!wasInserted) {
154e8d8bef9SDimitry Andric     if (auto *defined = dyn_cast<Defined>(s)) {
155e8d8bef9SDimitry Andric       if (isWeakDef && !defined->isWeakDef())
156e8d8bef9SDimitry Andric         defined->overridesWeakDef = true;
157e8d8bef9SDimitry Andric     } else if (auto *undefined = dyn_cast<Undefined>(s)) {
158e8d8bef9SDimitry Andric       refState = undefined->refState;
159e8d8bef9SDimitry Andric     } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
160fe6060f1SDimitry Andric       refState = dysym->getRefState();
161e8d8bef9SDimitry Andric     }
162e8d8bef9SDimitry Andric   }
163e8d8bef9SDimitry Andric 
164fe6060f1SDimitry Andric   bool isDynamicLookup = file == nullptr;
165e8d8bef9SDimitry Andric   if (wasInserted || isa<Undefined>(s) ||
166fe6060f1SDimitry Andric       (isa<DylibSymbol>(s) &&
167fe6060f1SDimitry Andric        ((!isWeakDef && s->isWeakDef()) ||
168fe6060f1SDimitry Andric         (!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) {
169fe6060f1SDimitry Andric     if (auto *dynsym = dyn_cast<DylibSymbol>(s))
170fe6060f1SDimitry Andric       dynsym->unreference();
171e8d8bef9SDimitry Andric     replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv);
172fe6060f1SDimitry Andric   }
173e8d8bef9SDimitry Andric 
1745ffd83dbSDimitry Andric   return s;
1755ffd83dbSDimitry Andric }
1765ffd83dbSDimitry Andric 
177fe6060f1SDimitry Andric Symbol *SymbolTable::addDynamicLookup(StringRef name) {
178fe6060f1SDimitry Andric   return addDylib(name, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false);
179fe6060f1SDimitry Andric }
180fe6060f1SDimitry Andric 
1815ffd83dbSDimitry Andric Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file,
182e8d8bef9SDimitry Andric                              const object::Archive::Symbol &sym) {
1835ffd83dbSDimitry Andric   Symbol *s;
1845ffd83dbSDimitry Andric   bool wasInserted;
185fe6060f1SDimitry Andric   std::tie(s, wasInserted) = insert(name, file);
1865ffd83dbSDimitry Andric 
1875ffd83dbSDimitry Andric   if (wasInserted)
1885ffd83dbSDimitry Andric     replaceSymbol<LazySymbol>(s, file, sym);
189e8d8bef9SDimitry Andric   else if (isa<Undefined>(s) || (isa<DylibSymbol>(s) && s->isWeakDef()))
1905ffd83dbSDimitry Andric     file->fetch(sym);
1915ffd83dbSDimitry Andric   return s;
1925ffd83dbSDimitry Andric }
1935ffd83dbSDimitry Andric 
194fe6060f1SDimitry Andric Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
195fe6060f1SDimitry Andric                                    uint64_t value, bool isPrivateExtern,
196fe6060f1SDimitry Andric                                    bool includeInSymtab,
197fe6060f1SDimitry Andric                                    bool referencedDynamically) {
198*349cc55cSDimitry Andric   Defined *s =
199*349cc55cSDimitry Andric       addDefined(name, nullptr, isec, value, /*size=*/0,
200fe6060f1SDimitry Andric                  /*isWeakDef=*/false, isPrivateExtern,
201fe6060f1SDimitry Andric                  /*isThumb=*/false, referencedDynamically,
202*349cc55cSDimitry Andric                  /*noDeadStrip=*/false, /*isWeakDefCanBeHidden=*/false);
203fe6060f1SDimitry Andric   s->includeInSymtab = includeInSymtab;
204e8d8bef9SDimitry Andric   return s;
205e8d8bef9SDimitry Andric }
206e8d8bef9SDimitry Andric 
207fe6060f1SDimitry Andric enum class Boundary {
208fe6060f1SDimitry Andric   Start,
209fe6060f1SDimitry Andric   End,
210fe6060f1SDimitry Andric };
211fe6060f1SDimitry Andric 
212fe6060f1SDimitry Andric static Defined *createBoundarySymbol(const Undefined &sym) {
213fe6060f1SDimitry Andric   return symtab->addSynthetic(
214fe6060f1SDimitry Andric       sym.getName(), /*isec=*/nullptr, /*value=*/-1, /*isPrivateExtern=*/true,
215fe6060f1SDimitry Andric       /*includeInSymtab=*/false, /*referencedDynamically=*/false);
216fe6060f1SDimitry Andric }
217fe6060f1SDimitry Andric 
218fe6060f1SDimitry Andric static void handleSectionBoundarySymbol(const Undefined &sym, StringRef segSect,
219fe6060f1SDimitry Andric                                         Boundary which) {
220fe6060f1SDimitry Andric   StringRef segName, sectName;
221fe6060f1SDimitry Andric   std::tie(segName, sectName) = segSect.split('$');
222fe6060f1SDimitry Andric 
223fe6060f1SDimitry Andric   // Attach the symbol to any InputSection that will end up in the right
224fe6060f1SDimitry Andric   // OutputSection -- it doesn't matter which one we pick.
225fe6060f1SDimitry Andric   // Don't bother looking through inputSections for a matching
226fe6060f1SDimitry Andric   // ConcatInputSection -- we need to create ConcatInputSection for
227fe6060f1SDimitry Andric   // non-existing sections anyways, and that codepath works even if we should
228fe6060f1SDimitry Andric   // already have a ConcatInputSection with the right name.
229fe6060f1SDimitry Andric 
230fe6060f1SDimitry Andric   OutputSection *osec = nullptr;
231fe6060f1SDimitry Andric   // This looks for __TEXT,__cstring etc.
232fe6060f1SDimitry Andric   for (SyntheticSection *ssec : syntheticSections)
233fe6060f1SDimitry Andric     if (ssec->segname == segName && ssec->name == sectName) {
234fe6060f1SDimitry Andric       osec = ssec->isec->parent;
235e8d8bef9SDimitry Andric       break;
236fe6060f1SDimitry Andric     }
237fe6060f1SDimitry Andric 
238fe6060f1SDimitry Andric   if (!osec) {
239fe6060f1SDimitry Andric     ConcatInputSection *isec = make<ConcatInputSection>(segName, sectName);
240fe6060f1SDimitry Andric 
241fe6060f1SDimitry Andric     // This runs after markLive() and is only called for Undefineds that are
242fe6060f1SDimitry Andric     // live. Marking the isec live ensures an OutputSection is created that the
243fe6060f1SDimitry Andric     // start/end symbol can refer to.
244fe6060f1SDimitry Andric     assert(sym.isLive());
245fe6060f1SDimitry Andric     isec->live = true;
246fe6060f1SDimitry Andric 
247fe6060f1SDimitry Andric     // This runs after gatherInputSections(), so need to explicitly set parent
248fe6060f1SDimitry Andric     // and add to inputSections.
249fe6060f1SDimitry Andric     osec = isec->parent = ConcatOutputSection::getOrCreateForInput(isec);
250fe6060f1SDimitry Andric     inputSections.push_back(isec);
251fe6060f1SDimitry Andric   }
252fe6060f1SDimitry Andric 
253fe6060f1SDimitry Andric   if (which == Boundary::Start)
254fe6060f1SDimitry Andric     osec->sectionStartSymbols.push_back(createBoundarySymbol(sym));
255fe6060f1SDimitry Andric   else
256fe6060f1SDimitry Andric     osec->sectionEndSymbols.push_back(createBoundarySymbol(sym));
257fe6060f1SDimitry Andric }
258fe6060f1SDimitry Andric 
259fe6060f1SDimitry Andric static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
260fe6060f1SDimitry Andric                                         Boundary which) {
261fe6060f1SDimitry Andric   OutputSegment *seg = getOrCreateOutputSegment(segName);
262fe6060f1SDimitry Andric   if (which == Boundary::Start)
263fe6060f1SDimitry Andric     seg->segmentStartSymbols.push_back(createBoundarySymbol(sym));
264fe6060f1SDimitry Andric   else
265fe6060f1SDimitry Andric     seg->segmentEndSymbols.push_back(createBoundarySymbol(sym));
266fe6060f1SDimitry Andric }
267fe6060f1SDimitry Andric 
268fe6060f1SDimitry Andric void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
269fe6060f1SDimitry Andric   // Handle start/end symbols.
270fe6060f1SDimitry Andric   StringRef name = sym.getName();
271fe6060f1SDimitry Andric   if (name.consume_front("section$start$"))
272fe6060f1SDimitry Andric     return handleSectionBoundarySymbol(sym, name, Boundary::Start);
273fe6060f1SDimitry Andric   if (name.consume_front("section$end$"))
274fe6060f1SDimitry Andric     return handleSectionBoundarySymbol(sym, name, Boundary::End);
275fe6060f1SDimitry Andric   if (name.consume_front("segment$start$"))
276fe6060f1SDimitry Andric     return handleSegmentBoundarySymbol(sym, name, Boundary::Start);
277fe6060f1SDimitry Andric   if (name.consume_front("segment$end$"))
278fe6060f1SDimitry Andric     return handleSegmentBoundarySymbol(sym, name, Boundary::End);
279fe6060f1SDimitry Andric 
280fe6060f1SDimitry Andric   // Handle -U.
281fe6060f1SDimitry Andric   if (config->explicitDynamicLookups.count(sym.getName())) {
282fe6060f1SDimitry Andric     symtab->addDynamicLookup(sym.getName());
283fe6060f1SDimitry Andric     return;
284fe6060f1SDimitry Andric   }
285fe6060f1SDimitry Andric 
286fe6060f1SDimitry Andric   // Handle -undefined.
287fe6060f1SDimitry Andric   auto message = [source, &sym]() {
288fe6060f1SDimitry Andric     std::string message = "undefined symbol";
289fe6060f1SDimitry Andric     if (config->archMultiple)
290fe6060f1SDimitry Andric       message += (" for arch " + getArchitectureName(config->arch())).str();
291fe6060f1SDimitry Andric     message += ": " + toString(sym);
292fe6060f1SDimitry Andric     if (!source.empty())
293fe6060f1SDimitry Andric       message += "\n>>> referenced by " + source.str();
294fe6060f1SDimitry Andric     else
295fe6060f1SDimitry Andric       message += "\n>>> referenced by " + toString(sym.getFile());
296fe6060f1SDimitry Andric     return message;
297fe6060f1SDimitry Andric   };
298fe6060f1SDimitry Andric   switch (config->undefinedSymbolTreatment) {
299e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::error:
300fe6060f1SDimitry Andric     error(message());
301e8d8bef9SDimitry Andric     break;
302e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::warning:
303fe6060f1SDimitry Andric     warn(message());
304fe6060f1SDimitry Andric     LLVM_FALLTHROUGH;
305e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::dynamic_lookup:
306fe6060f1SDimitry Andric   case UndefinedSymbolTreatment::suppress:
307fe6060f1SDimitry Andric     symtab->addDynamicLookup(sym.getName());
308e8d8bef9SDimitry Andric     break;
309e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::unknown:
310e8d8bef9SDimitry Andric     llvm_unreachable("unknown -undefined TREATMENT");
311e8d8bef9SDimitry Andric   }
312e8d8bef9SDimitry Andric }
313e8d8bef9SDimitry Andric 
3145ffd83dbSDimitry Andric SymbolTable *macho::symtab;
315