1 //===- SymbolTable.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SymbolTable.h" 10 #include "Config.h" 11 #include "InputFiles.h" 12 #include "Symbols.h" 13 #include "lld/Common/ErrorHandler.h" 14 #include "lld/Common/Memory.h" 15 16 using namespace llvm; 17 using namespace lld; 18 using namespace lld::macho; 19 20 Symbol *SymbolTable::find(CachedHashStringRef cachedName) { 21 auto it = symMap.find(cachedName); 22 if (it == symMap.end()) 23 return nullptr; 24 return symVector[it->second]; 25 } 26 27 std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, 28 const InputFile *file) { 29 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 30 31 Symbol *sym; 32 if (!p.second) { 33 // Name already present in the symbol table. 34 sym = symVector[p.first->second]; 35 } else { 36 // Name is a new symbol. 37 sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 38 symVector.push_back(sym); 39 } 40 41 sym->isUsedInRegularObj |= !file || isa<ObjFile>(file); 42 return {sym, p.second}; 43 } 44 45 Defined *SymbolTable::addDefined(StringRef name, InputFile *file, 46 InputSection *isec, uint64_t value, 47 uint64_t size, bool isWeakDef, 48 bool isPrivateExtern, bool isThumb) { 49 Symbol *s; 50 bool wasInserted; 51 bool overridesWeakDef = false; 52 std::tie(s, wasInserted) = insert(name, file); 53 54 assert(!isWeakDef || (isa<BitcodeFile>(file) && !isec) || 55 (isa<ObjFile>(file) && file == isec->file)); 56 57 if (!wasInserted) { 58 if (auto *defined = dyn_cast<Defined>(s)) { 59 if (isWeakDef) { 60 // Both old and new symbol weak (e.g. inline function in two TUs): 61 // If one of them isn't private extern, the merged symbol isn't. 62 if (defined->isWeakDef()) { 63 defined->privateExtern &= isPrivateExtern; 64 65 // FIXME: Handle this for bitcode files. 66 // FIXME: We currently only do this if both symbols are weak. 67 // We could do this if either is weak (but getting the 68 // case where !isWeakDef && defined->isWeakDef() right 69 // requires some care and testing). 70 if (isec) 71 isec->canOmitFromOutput = true; 72 } 73 74 return defined; 75 } 76 if (!defined->isWeakDef()) 77 error("duplicate symbol: " + name + "\n>>> defined in " + 78 toString(defined->getFile()) + "\n>>> defined in " + 79 toString(file)); 80 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 81 overridesWeakDef = !isWeakDef && dysym->isWeakDef(); 82 } 83 // Defined symbols take priority over other types of symbols, so in case 84 // of a name conflict, we fall through to the replaceSymbol() call below. 85 } 86 87 Defined *defined = 88 replaceSymbol<Defined>(s, name, file, isec, value, size, isWeakDef, 89 /*isExternal=*/true, isPrivateExtern, isThumb); 90 defined->overridesWeakDef = overridesWeakDef; 91 return defined; 92 } 93 94 Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file, 95 bool isWeakRef) { 96 Symbol *s; 97 bool wasInserted; 98 std::tie(s, wasInserted) = insert(name, file); 99 100 RefState refState = isWeakRef ? RefState::Weak : RefState::Strong; 101 102 if (wasInserted) 103 replaceSymbol<Undefined>(s, name, file, refState); 104 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 105 lazy->fetchArchiveMember(); 106 else if (auto *dynsym = dyn_cast<DylibSymbol>(s)) 107 dynsym->refState = std::max(dynsym->refState, refState); 108 else if (auto *undefined = dyn_cast<Undefined>(s)) 109 undefined->refState = std::max(undefined->refState, refState); 110 return s; 111 } 112 113 Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size, 114 uint32_t align, bool isPrivateExtern) { 115 Symbol *s; 116 bool wasInserted; 117 std::tie(s, wasInserted) = insert(name, file); 118 119 if (!wasInserted) { 120 if (auto *common = dyn_cast<CommonSymbol>(s)) { 121 if (size < common->size) 122 return s; 123 } else if (isa<Defined>(s)) { 124 return s; 125 } 126 // Common symbols take priority over all non-Defined symbols, so in case of 127 // a name conflict, we fall through to the replaceSymbol() call below. 128 } 129 130 replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern); 131 return s; 132 } 133 134 Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef, 135 bool isTlv) { 136 Symbol *s; 137 bool wasInserted; 138 std::tie(s, wasInserted) = insert(name, file); 139 140 RefState refState = RefState::Unreferenced; 141 if (!wasInserted) { 142 if (auto *defined = dyn_cast<Defined>(s)) { 143 if (isWeakDef && !defined->isWeakDef()) 144 defined->overridesWeakDef = true; 145 } else if (auto *undefined = dyn_cast<Undefined>(s)) { 146 refState = undefined->refState; 147 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 148 refState = dysym->refState; 149 } 150 } 151 152 bool isDynamicLookup = file == nullptr; 153 if (wasInserted || isa<Undefined>(s) || 154 (isa<DylibSymbol>(s) && 155 ((!isWeakDef && s->isWeakDef()) || 156 (!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) 157 replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv); 158 159 return s; 160 } 161 162 Symbol *SymbolTable::addDynamicLookup(StringRef name) { 163 return addDylib(name, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false); 164 } 165 166 Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file, 167 const object::Archive::Symbol &sym) { 168 Symbol *s; 169 bool wasInserted; 170 std::tie(s, wasInserted) = insert(name, file); 171 172 if (wasInserted) 173 replaceSymbol<LazySymbol>(s, file, sym); 174 else if (isa<Undefined>(s) || (isa<DylibSymbol>(s) && s->isWeakDef())) 175 file->fetch(sym); 176 return s; 177 } 178 179 Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec, 180 uint64_t value, bool isPrivateExtern, 181 bool includeInSymtab) { 182 Defined *s = addDefined(name, nullptr, isec, value, /*size=*/0, 183 /*isWeakDef=*/false, isPrivateExtern, 184 /*isThumb=*/false); 185 s->includeInSymtab = includeInSymtab; 186 return s; 187 } 188 189 void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) { 190 auto message = [source, &sym]() { 191 std::string message = "undefined symbol: " + toString(sym); 192 if (!source.empty()) 193 message += "\n>>> referenced by " + source.str(); 194 else 195 message += "\n>>> referenced by " + toString(sym.getFile()); 196 return message; 197 }; 198 switch (config->undefinedSymbolTreatment) { 199 case UndefinedSymbolTreatment::error: 200 error(message()); 201 break; 202 case UndefinedSymbolTreatment::warning: 203 warn(message()); 204 LLVM_FALLTHROUGH; 205 case UndefinedSymbolTreatment::dynamic_lookup: 206 case UndefinedSymbolTreatment::suppress: 207 symtab->addDynamicLookup(sym.getName()); 208 break; 209 case UndefinedSymbolTreatment::unknown: 210 llvm_unreachable("unknown -undefined TREATMENT"); 211 } 212 } 213 214 SymbolTable *macho::symtab; 215