xref: /freebsd-src/contrib/llvm-project/lld/MachO/SymbolTable.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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"
10*e8d8bef9SDimitry Andric #include "Config.h"
115ffd83dbSDimitry Andric #include "InputFiles.h"
125ffd83dbSDimitry Andric #include "Symbols.h"
135ffd83dbSDimitry Andric #include "lld/Common/ErrorHandler.h"
145ffd83dbSDimitry Andric #include "lld/Common/Memory.h"
155ffd83dbSDimitry Andric 
165ffd83dbSDimitry Andric using namespace llvm;
175ffd83dbSDimitry Andric using namespace lld;
185ffd83dbSDimitry Andric using namespace lld::macho;
195ffd83dbSDimitry Andric 
205ffd83dbSDimitry Andric Symbol *SymbolTable::find(StringRef name) {
21*e8d8bef9SDimitry Andric   auto it = symMap.find(CachedHashStringRef(name));
225ffd83dbSDimitry Andric   if (it == symMap.end())
235ffd83dbSDimitry Andric     return nullptr;
245ffd83dbSDimitry Andric   return symVector[it->second];
255ffd83dbSDimitry Andric }
265ffd83dbSDimitry Andric 
275ffd83dbSDimitry Andric std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
285ffd83dbSDimitry Andric   auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
295ffd83dbSDimitry Andric 
305ffd83dbSDimitry Andric   // Name already present in the symbol table.
315ffd83dbSDimitry Andric   if (!p.second)
325ffd83dbSDimitry Andric     return {symVector[p.first->second], false};
335ffd83dbSDimitry Andric 
345ffd83dbSDimitry Andric   // Name is a new symbol.
355ffd83dbSDimitry Andric   Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
365ffd83dbSDimitry Andric   symVector.push_back(sym);
375ffd83dbSDimitry Andric   return {sym, true};
385ffd83dbSDimitry Andric }
395ffd83dbSDimitry Andric 
405ffd83dbSDimitry Andric Symbol *SymbolTable::addDefined(StringRef name, InputSection *isec,
41*e8d8bef9SDimitry Andric                                 uint32_t value, bool isWeakDef,
42*e8d8bef9SDimitry Andric                                 bool isPrivateExtern) {
435ffd83dbSDimitry Andric   Symbol *s;
445ffd83dbSDimitry Andric   bool wasInserted;
45*e8d8bef9SDimitry Andric   bool overridesWeakDef = false;
465ffd83dbSDimitry Andric   std::tie(s, wasInserted) = insert(name);
475ffd83dbSDimitry Andric 
48*e8d8bef9SDimitry Andric   if (!wasInserted) {
49*e8d8bef9SDimitry Andric     if (auto *defined = dyn_cast<Defined>(s)) {
50*e8d8bef9SDimitry Andric       if (isWeakDef) {
51*e8d8bef9SDimitry Andric         // Both old and new symbol weak (e.g. inline function in two TUs):
52*e8d8bef9SDimitry Andric         // If one of them isn't private extern, the merged symbol isn't.
53*e8d8bef9SDimitry Andric         if (defined->isWeakDef())
54*e8d8bef9SDimitry Andric           defined->privateExtern &= isPrivateExtern;
55*e8d8bef9SDimitry Andric         return s;
56*e8d8bef9SDimitry Andric       }
57*e8d8bef9SDimitry Andric       if (!defined->isWeakDef())
585ffd83dbSDimitry Andric         error("duplicate symbol: " + name);
59*e8d8bef9SDimitry Andric     } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
60*e8d8bef9SDimitry Andric       overridesWeakDef = !isWeakDef && dysym->isWeakDef();
61*e8d8bef9SDimitry Andric     }
62*e8d8bef9SDimitry Andric     // Defined symbols take priority over other types of symbols, so in case
63*e8d8bef9SDimitry Andric     // of a name conflict, we fall through to the replaceSymbol() call below.
64*e8d8bef9SDimitry Andric   }
655ffd83dbSDimitry Andric 
66*e8d8bef9SDimitry Andric   Defined *defined =
67*e8d8bef9SDimitry Andric       replaceSymbol<Defined>(s, name, isec, value, isWeakDef,
68*e8d8bef9SDimitry Andric                              /*isExternal=*/true, isPrivateExtern);
69*e8d8bef9SDimitry Andric   defined->overridesWeakDef = overridesWeakDef;
705ffd83dbSDimitry Andric   return s;
715ffd83dbSDimitry Andric }
725ffd83dbSDimitry Andric 
73*e8d8bef9SDimitry Andric Symbol *SymbolTable::addUndefined(StringRef name, bool isWeakRef) {
745ffd83dbSDimitry Andric   Symbol *s;
755ffd83dbSDimitry Andric   bool wasInserted;
765ffd83dbSDimitry Andric   std::tie(s, wasInserted) = insert(name);
775ffd83dbSDimitry Andric 
78*e8d8bef9SDimitry Andric   auto refState = isWeakRef ? RefState::Weak : RefState::Strong;
79*e8d8bef9SDimitry Andric 
805ffd83dbSDimitry Andric   if (wasInserted)
81*e8d8bef9SDimitry Andric     replaceSymbol<Undefined>(s, name, refState);
82*e8d8bef9SDimitry Andric   else if (auto *lazy = dyn_cast<LazySymbol>(s))
835ffd83dbSDimitry Andric     lazy->fetchArchiveMember();
84*e8d8bef9SDimitry Andric   else if (auto *dynsym = dyn_cast<DylibSymbol>(s))
85*e8d8bef9SDimitry Andric     dynsym->refState = std::max(dynsym->refState, refState);
86*e8d8bef9SDimitry Andric   else if (auto *undefined = dyn_cast<Undefined>(s))
87*e8d8bef9SDimitry Andric     undefined->refState = std::max(undefined->refState, refState);
885ffd83dbSDimitry Andric   return s;
895ffd83dbSDimitry Andric }
905ffd83dbSDimitry Andric 
91*e8d8bef9SDimitry Andric Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size,
92*e8d8bef9SDimitry Andric                                uint32_t align, bool isPrivateExtern) {
935ffd83dbSDimitry Andric   Symbol *s;
945ffd83dbSDimitry Andric   bool wasInserted;
955ffd83dbSDimitry Andric   std::tie(s, wasInserted) = insert(name);
965ffd83dbSDimitry Andric 
97*e8d8bef9SDimitry Andric   if (!wasInserted) {
98*e8d8bef9SDimitry Andric     if (auto *common = dyn_cast<CommonSymbol>(s)) {
99*e8d8bef9SDimitry Andric       if (size < common->size)
100*e8d8bef9SDimitry Andric         return s;
101*e8d8bef9SDimitry Andric     } else if (isa<Defined>(s)) {
102*e8d8bef9SDimitry Andric       return s;
103*e8d8bef9SDimitry Andric     }
104*e8d8bef9SDimitry Andric     // Common symbols take priority over all non-Defined symbols, so in case of
105*e8d8bef9SDimitry Andric     // a name conflict, we fall through to the replaceSymbol() call below.
106*e8d8bef9SDimitry Andric   }
107*e8d8bef9SDimitry Andric 
108*e8d8bef9SDimitry Andric   replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern);
109*e8d8bef9SDimitry Andric   return s;
110*e8d8bef9SDimitry Andric }
111*e8d8bef9SDimitry Andric 
112*e8d8bef9SDimitry Andric Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef,
113*e8d8bef9SDimitry Andric                               bool isTlv) {
114*e8d8bef9SDimitry Andric   Symbol *s;
115*e8d8bef9SDimitry Andric   bool wasInserted;
116*e8d8bef9SDimitry Andric   std::tie(s, wasInserted) = insert(name);
117*e8d8bef9SDimitry Andric 
118*e8d8bef9SDimitry Andric   auto refState = RefState::Unreferenced;
119*e8d8bef9SDimitry Andric   if (!wasInserted) {
120*e8d8bef9SDimitry Andric     if (auto *defined = dyn_cast<Defined>(s)) {
121*e8d8bef9SDimitry Andric       if (isWeakDef && !defined->isWeakDef())
122*e8d8bef9SDimitry Andric         defined->overridesWeakDef = true;
123*e8d8bef9SDimitry Andric     } else if (auto *undefined = dyn_cast<Undefined>(s)) {
124*e8d8bef9SDimitry Andric       refState = undefined->refState;
125*e8d8bef9SDimitry Andric     } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
126*e8d8bef9SDimitry Andric       refState = dysym->refState;
127*e8d8bef9SDimitry Andric     }
128*e8d8bef9SDimitry Andric   }
129*e8d8bef9SDimitry Andric 
130*e8d8bef9SDimitry Andric   if (wasInserted || isa<Undefined>(s) ||
131*e8d8bef9SDimitry Andric       (isa<DylibSymbol>(s) && !isWeakDef && s->isWeakDef()))
132*e8d8bef9SDimitry Andric     replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv);
133*e8d8bef9SDimitry Andric 
1345ffd83dbSDimitry Andric   return s;
1355ffd83dbSDimitry Andric }
1365ffd83dbSDimitry Andric 
1375ffd83dbSDimitry Andric Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file,
138*e8d8bef9SDimitry Andric                              const object::Archive::Symbol &sym) {
1395ffd83dbSDimitry Andric   Symbol *s;
1405ffd83dbSDimitry Andric   bool wasInserted;
1415ffd83dbSDimitry Andric   std::tie(s, wasInserted) = insert(name);
1425ffd83dbSDimitry Andric 
1435ffd83dbSDimitry Andric   if (wasInserted)
1445ffd83dbSDimitry Andric     replaceSymbol<LazySymbol>(s, file, sym);
145*e8d8bef9SDimitry Andric   else if (isa<Undefined>(s) || (isa<DylibSymbol>(s) && s->isWeakDef()))
1465ffd83dbSDimitry Andric     file->fetch(sym);
1475ffd83dbSDimitry Andric   return s;
1485ffd83dbSDimitry Andric }
1495ffd83dbSDimitry Andric 
150*e8d8bef9SDimitry Andric Symbol *SymbolTable::addDSOHandle(const MachHeaderSection *header) {
151*e8d8bef9SDimitry Andric   Symbol *s;
152*e8d8bef9SDimitry Andric   bool wasInserted;
153*e8d8bef9SDimitry Andric   std::tie(s, wasInserted) = insert(DSOHandle::name);
154*e8d8bef9SDimitry Andric   if (!wasInserted) {
155*e8d8bef9SDimitry Andric     // FIXME: Make every symbol (including absolute symbols) contain a
156*e8d8bef9SDimitry Andric     // reference to their originating file, then add that file name to this
157*e8d8bef9SDimitry Andric     // error message.
158*e8d8bef9SDimitry Andric     if (isa<Defined>(s))
159*e8d8bef9SDimitry Andric       error("found defined symbol with illegal name " + DSOHandle::name);
160*e8d8bef9SDimitry Andric   }
161*e8d8bef9SDimitry Andric   replaceSymbol<DSOHandle>(s, header);
162*e8d8bef9SDimitry Andric   return s;
163*e8d8bef9SDimitry Andric }
164*e8d8bef9SDimitry Andric 
165*e8d8bef9SDimitry Andric void lld::macho::treatUndefinedSymbol(StringRef symbolName,
166*e8d8bef9SDimitry Andric                                       StringRef fileName) {
167*e8d8bef9SDimitry Andric   std::string message = ("undefined symbol: " + symbolName).str();
168*e8d8bef9SDimitry Andric   if (!fileName.empty())
169*e8d8bef9SDimitry Andric     message += ("\n>>> referenced by " + fileName).str();
170*e8d8bef9SDimitry Andric   switch (config->undefinedSymbolTreatment) {
171*e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::suppress:
172*e8d8bef9SDimitry Andric     break;
173*e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::error:
174*e8d8bef9SDimitry Andric     error(message);
175*e8d8bef9SDimitry Andric     break;
176*e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::warning:
177*e8d8bef9SDimitry Andric     warn(message);
178*e8d8bef9SDimitry Andric     break;
179*e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::dynamic_lookup:
180*e8d8bef9SDimitry Andric     error("dynamic_lookup unimplemented for " + message);
181*e8d8bef9SDimitry Andric     break;
182*e8d8bef9SDimitry Andric   case UndefinedSymbolTreatment::unknown:
183*e8d8bef9SDimitry Andric     llvm_unreachable("unknown -undefined TREATMENT");
184*e8d8bef9SDimitry Andric   }
185*e8d8bef9SDimitry Andric }
186*e8d8bef9SDimitry Andric 
1875ffd83dbSDimitry Andric SymbolTable *macho::symtab;
188