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 bool isReferencedDynamically, 50 bool noDeadStrip) { 51 Symbol *s; 52 bool wasInserted; 53 bool overridesWeakDef = false; 54 std::tie(s, wasInserted) = insert(name, file); 55 56 assert(!isWeakDef || (isa<BitcodeFile>(file) && !isec) || 57 (isa<ObjFile>(file) && file == isec->file)); 58 59 if (!wasInserted) { 60 if (auto *defined = dyn_cast<Defined>(s)) { 61 if (isWeakDef) { 62 if (defined->isWeakDef()) { 63 // Both old and new symbol weak (e.g. inline function in two TUs): 64 // If one of them isn't private extern, the merged symbol isn't. 65 defined->privateExtern &= isPrivateExtern; 66 defined->referencedDynamically |= isReferencedDynamically; 67 defined->noDeadStrip |= noDeadStrip; 68 69 // FIXME: Handle this for bitcode files. 70 // FIXME: We currently only do this if both symbols are weak. 71 // We could do this if either is weak (but getting the 72 // case where !isWeakDef && defined->isWeakDef() right 73 // requires some care and testing). 74 if (isec) 75 isec->wasCoalesced = true; 76 } 77 78 return defined; 79 } 80 if (!defined->isWeakDef()) 81 error("duplicate symbol: " + name + "\n>>> defined in " + 82 toString(defined->getFile()) + "\n>>> defined in " + 83 toString(file)); 84 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 85 overridesWeakDef = !isWeakDef && dysym->isWeakDef(); 86 dysym->unreference(); 87 } 88 // Defined symbols take priority over other types of symbols, so in case 89 // of a name conflict, we fall through to the replaceSymbol() call below. 90 } 91 92 Defined *defined = replaceSymbol<Defined>( 93 s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true, 94 isPrivateExtern, isThumb, isReferencedDynamically, noDeadStrip); 95 defined->overridesWeakDef = overridesWeakDef; 96 return defined; 97 } 98 99 Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file, 100 bool isWeakRef) { 101 Symbol *s; 102 bool wasInserted; 103 std::tie(s, wasInserted) = insert(name, file); 104 105 RefState refState = isWeakRef ? RefState::Weak : RefState::Strong; 106 107 if (wasInserted) 108 replaceSymbol<Undefined>(s, name, file, refState); 109 else if (auto *lazy = dyn_cast<LazySymbol>(s)) 110 lazy->fetchArchiveMember(); 111 else if (auto *dynsym = dyn_cast<DylibSymbol>(s)) 112 dynsym->reference(refState); 113 else if (auto *undefined = dyn_cast<Undefined>(s)) 114 undefined->refState = std::max(undefined->refState, refState); 115 return s; 116 } 117 118 Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size, 119 uint32_t align, bool isPrivateExtern) { 120 Symbol *s; 121 bool wasInserted; 122 std::tie(s, wasInserted) = insert(name, file); 123 124 if (!wasInserted) { 125 if (auto *common = dyn_cast<CommonSymbol>(s)) { 126 if (size < common->size) 127 return s; 128 } else if (isa<Defined>(s)) { 129 return s; 130 } 131 // Common symbols take priority over all non-Defined symbols, so in case of 132 // a name conflict, we fall through to the replaceSymbol() call below. 133 } 134 135 replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern); 136 return s; 137 } 138 139 Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef, 140 bool isTlv) { 141 Symbol *s; 142 bool wasInserted; 143 std::tie(s, wasInserted) = insert(name, file); 144 145 RefState refState = RefState::Unreferenced; 146 if (!wasInserted) { 147 if (auto *defined = dyn_cast<Defined>(s)) { 148 if (isWeakDef && !defined->isWeakDef()) 149 defined->overridesWeakDef = true; 150 } else if (auto *undefined = dyn_cast<Undefined>(s)) { 151 refState = undefined->refState; 152 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 153 refState = dysym->getRefState(); 154 } 155 } 156 157 bool isDynamicLookup = file == nullptr; 158 if (wasInserted || isa<Undefined>(s) || 159 (isa<DylibSymbol>(s) && 160 ((!isWeakDef && s->isWeakDef()) || 161 (!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) { 162 if (auto *dynsym = dyn_cast<DylibSymbol>(s)) 163 dynsym->unreference(); 164 replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv); 165 } 166 167 return s; 168 } 169 170 Symbol *SymbolTable::addDynamicLookup(StringRef name) { 171 return addDylib(name, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false); 172 } 173 174 Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file, 175 const object::Archive::Symbol &sym) { 176 Symbol *s; 177 bool wasInserted; 178 std::tie(s, wasInserted) = insert(name, file); 179 180 if (wasInserted) 181 replaceSymbol<LazySymbol>(s, file, sym); 182 else if (isa<Undefined>(s) || (isa<DylibSymbol>(s) && s->isWeakDef())) 183 file->fetch(sym); 184 return s; 185 } 186 187 Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec, 188 uint64_t value, bool isPrivateExtern, 189 bool includeInSymtab, 190 bool referencedDynamically) { 191 Defined *s = addDefined(name, nullptr, isec, value, /*size=*/0, 192 /*isWeakDef=*/false, isPrivateExtern, 193 /*isThumb=*/false, referencedDynamically, 194 /*noDeadStrip=*/false); 195 s->includeInSymtab = includeInSymtab; 196 return s; 197 } 198 199 void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) { 200 auto message = [source, &sym]() { 201 std::string message = "undefined symbol: " + toString(sym); 202 if (!source.empty()) 203 message += "\n>>> referenced by " + source.str(); 204 else 205 message += "\n>>> referenced by " + toString(sym.getFile()); 206 return message; 207 }; 208 switch (config->undefinedSymbolTreatment) { 209 case UndefinedSymbolTreatment::error: 210 error(message()); 211 break; 212 case UndefinedSymbolTreatment::warning: 213 warn(message()); 214 LLVM_FALLTHROUGH; 215 case UndefinedSymbolTreatment::dynamic_lookup: 216 case UndefinedSymbolTreatment::suppress: 217 symtab->addDynamicLookup(sym.getName()); 218 break; 219 case UndefinedSymbolTreatment::unknown: 220 llvm_unreachable("unknown -undefined TREATMENT"); 221 } 222 } 223 224 SymbolTable *macho::symtab; 225