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 "ConcatOutputSection.h" 11 #include "Config.h" 12 #include "InputFiles.h" 13 #include "InputSection.h" 14 #include "Symbols.h" 15 #include "SyntheticSections.h" 16 #include "lld/Common/ErrorHandler.h" 17 #include "lld/Common/Memory.h" 18 19 using namespace llvm; 20 using namespace lld; 21 using namespace lld::macho; 22 23 Symbol *SymbolTable::find(CachedHashStringRef cachedName) { 24 auto it = symMap.find(cachedName); 25 if (it == symMap.end()) 26 return nullptr; 27 return symVector[it->second]; 28 } 29 30 std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, 31 const InputFile *file) { 32 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); 33 34 Symbol *sym; 35 if (!p.second) { 36 // Name already present in the symbol table. 37 sym = symVector[p.first->second]; 38 } else { 39 // Name is a new symbol. 40 sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 41 symVector.push_back(sym); 42 } 43 44 sym->isUsedInRegularObj |= !file || isa<ObjFile>(file); 45 return {sym, p.second}; 46 } 47 48 Defined *SymbolTable::addDefined(StringRef name, InputFile *file, 49 InputSection *isec, uint64_t value, 50 uint64_t size, bool isWeakDef, 51 bool isPrivateExtern, bool isThumb, 52 bool isReferencedDynamically, bool noDeadStrip, 53 bool isWeakDefCanBeHidden) { 54 Symbol *s; 55 bool wasInserted; 56 bool overridesWeakDef = false; 57 std::tie(s, wasInserted) = insert(name, file); 58 59 assert(!isWeakDef || (isa<BitcodeFile>(file) && !isec) || 60 (isa<ObjFile>(file) && file == isec->getFile())); 61 62 if (!wasInserted) { 63 if (auto *defined = dyn_cast<Defined>(s)) { 64 if (isWeakDef) { 65 // See further comment in createDefined() in InputFiles.cpp 66 if (defined->isWeakDef()) { 67 defined->privateExtern &= isPrivateExtern; 68 defined->weakDefCanBeHidden &= isWeakDefCanBeHidden; 69 defined->referencedDynamically |= isReferencedDynamically; 70 defined->noDeadStrip |= noDeadStrip; 71 } 72 // FIXME: Handle this for bitcode files. 73 if (auto concatIsec = dyn_cast_or_null<ConcatInputSection>(isec)) 74 concatIsec->wasCoalesced = true; 75 return defined; 76 } 77 78 if (defined->isWeakDef()) { 79 // FIXME: Handle this for bitcode files. 80 if (auto concatIsec = 81 dyn_cast_or_null<ConcatInputSection>(defined->isec)) { 82 concatIsec->wasCoalesced = true; 83 concatIsec->symbols.erase(llvm::find(concatIsec->symbols, defined)); 84 } 85 } else { 86 error("duplicate symbol: " + name + "\n>>> defined in " + 87 toString(defined->getFile()) + "\n>>> defined in " + 88 toString(file)); 89 } 90 91 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 92 overridesWeakDef = !isWeakDef && dysym->isWeakDef(); 93 dysym->unreference(); 94 } 95 // Defined symbols take priority over other types of symbols, so in case 96 // of a name conflict, we fall through to the replaceSymbol() call below. 97 } 98 99 // With -flat_namespace, all extern symbols in dylibs are interposable. 100 // FIXME: Add support for `-interposable` (PR53680). 101 bool interposable = config->namespaceKind == NamespaceKind::flat && 102 config->outputType != MachO::MH_EXECUTE && 103 !isPrivateExtern; 104 Defined *defined = replaceSymbol<Defined>( 105 s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true, 106 isPrivateExtern, isThumb, isReferencedDynamically, noDeadStrip, 107 overridesWeakDef, isWeakDefCanBeHidden, interposable); 108 return defined; 109 } 110 111 Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file, 112 bool isWeakRef) { 113 Symbol *s; 114 bool wasInserted; 115 std::tie(s, wasInserted) = insert(name, file); 116 117 RefState refState = isWeakRef ? RefState::Weak : RefState::Strong; 118 119 if (wasInserted) 120 replaceSymbol<Undefined>(s, name, file, refState); 121 else if (auto *lazy = dyn_cast<LazyArchive>(s)) 122 lazy->fetchArchiveMember(); 123 else if (isa<LazyObject>(s)) 124 extract(*s->getFile(), s->getName()); 125 else if (auto *dynsym = dyn_cast<DylibSymbol>(s)) 126 dynsym->reference(refState); 127 else if (auto *undefined = dyn_cast<Undefined>(s)) 128 undefined->refState = std::max(undefined->refState, refState); 129 return s; 130 } 131 132 Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size, 133 uint32_t align, bool isPrivateExtern) { 134 Symbol *s; 135 bool wasInserted; 136 std::tie(s, wasInserted) = insert(name, file); 137 138 if (!wasInserted) { 139 if (auto *common = dyn_cast<CommonSymbol>(s)) { 140 if (size < common->size) 141 return s; 142 } else if (isa<Defined>(s)) { 143 return s; 144 } 145 // Common symbols take priority over all non-Defined symbols, so in case of 146 // a name conflict, we fall through to the replaceSymbol() call below. 147 } 148 149 replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern); 150 return s; 151 } 152 153 Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef, 154 bool isTlv) { 155 Symbol *s; 156 bool wasInserted; 157 std::tie(s, wasInserted) = insert(name, file); 158 159 RefState refState = RefState::Unreferenced; 160 if (!wasInserted) { 161 if (auto *defined = dyn_cast<Defined>(s)) { 162 if (isWeakDef && !defined->isWeakDef()) 163 defined->overridesWeakDef = true; 164 } else if (auto *undefined = dyn_cast<Undefined>(s)) { 165 refState = undefined->refState; 166 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 167 refState = dysym->getRefState(); 168 } 169 } 170 171 bool isDynamicLookup = file == nullptr; 172 if (wasInserted || isa<Undefined>(s) || 173 (isa<DylibSymbol>(s) && 174 ((!isWeakDef && s->isWeakDef()) || 175 (!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) { 176 if (auto *dynsym = dyn_cast<DylibSymbol>(s)) 177 dynsym->unreference(); 178 replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv); 179 } 180 181 return s; 182 } 183 184 Symbol *SymbolTable::addDynamicLookup(StringRef name) { 185 return addDylib(name, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false); 186 } 187 188 Symbol *SymbolTable::addLazyArchive(StringRef name, ArchiveFile *file, 189 const object::Archive::Symbol &sym) { 190 Symbol *s; 191 bool wasInserted; 192 std::tie(s, wasInserted) = insert(name, file); 193 194 if (wasInserted) { 195 replaceSymbol<LazyArchive>(s, file, sym); 196 } else if (isa<Undefined>(s)) { 197 file->fetch(sym); 198 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 199 if (dysym->isWeakDef()) { 200 if (dysym->getRefState() != RefState::Unreferenced) 201 file->fetch(sym); 202 else 203 replaceSymbol<LazyArchive>(s, file, sym); 204 } 205 } 206 return s; 207 } 208 209 Symbol *SymbolTable::addLazyObject(StringRef name, InputFile &file) { 210 Symbol *s; 211 bool wasInserted; 212 std::tie(s, wasInserted) = insert(name, &file); 213 214 if (wasInserted) { 215 replaceSymbol<LazyObject>(s, file, name); 216 } else if (isa<Undefined>(s)) { 217 extract(file, name); 218 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) { 219 if (dysym->isWeakDef()) { 220 if (dysym->getRefState() != RefState::Unreferenced) 221 extract(file, name); 222 else 223 replaceSymbol<LazyObject>(s, file, name); 224 } 225 } 226 return s; 227 } 228 229 Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec, 230 uint64_t value, bool isPrivateExtern, 231 bool includeInSymtab, 232 bool referencedDynamically) { 233 assert(!isec || !isec->getFile()); // See makeSyntheticInputSection(). 234 Defined *s = 235 addDefined(name, /*file=*/nullptr, isec, value, /*size=*/0, 236 /*isWeakDef=*/false, isPrivateExtern, 237 /*isThumb=*/false, referencedDynamically, 238 /*noDeadStrip=*/false, /*isWeakDefCanBeHidden=*/false); 239 s->includeInSymtab = includeInSymtab; 240 return s; 241 } 242 243 enum class Boundary { 244 Start, 245 End, 246 }; 247 248 static Defined *createBoundarySymbol(const Undefined &sym) { 249 return symtab->addSynthetic( 250 sym.getName(), /*isec=*/nullptr, /*value=*/-1, /*isPrivateExtern=*/true, 251 /*includeInSymtab=*/false, /*referencedDynamically=*/false); 252 } 253 254 static void handleSectionBoundarySymbol(const Undefined &sym, StringRef segSect, 255 Boundary which) { 256 StringRef segName, sectName; 257 std::tie(segName, sectName) = segSect.split('$'); 258 259 // Attach the symbol to any InputSection that will end up in the right 260 // OutputSection -- it doesn't matter which one we pick. 261 // Don't bother looking through inputSections for a matching 262 // ConcatInputSection -- we need to create ConcatInputSection for 263 // non-existing sections anyways, and that codepath works even if we should 264 // already have a ConcatInputSection with the right name. 265 266 OutputSection *osec = nullptr; 267 // This looks for __TEXT,__cstring etc. 268 for (SyntheticSection *ssec : syntheticSections) 269 if (ssec->segname == segName && ssec->name == sectName) { 270 osec = ssec->isec->parent; 271 break; 272 } 273 274 if (!osec) { 275 ConcatInputSection *isec = makeSyntheticInputSection(segName, sectName); 276 277 // This runs after markLive() and is only called for Undefineds that are 278 // live. Marking the isec live ensures an OutputSection is created that the 279 // start/end symbol can refer to. 280 assert(sym.isLive()); 281 isec->live = true; 282 283 // This runs after gatherInputSections(), so need to explicitly set parent 284 // and add to inputSections. 285 osec = isec->parent = ConcatOutputSection::getOrCreateForInput(isec); 286 inputSections.push_back(isec); 287 } 288 289 if (which == Boundary::Start) 290 osec->sectionStartSymbols.push_back(createBoundarySymbol(sym)); 291 else 292 osec->sectionEndSymbols.push_back(createBoundarySymbol(sym)); 293 } 294 295 static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName, 296 Boundary which) { 297 OutputSegment *seg = getOrCreateOutputSegment(segName); 298 if (which == Boundary::Start) 299 seg->segmentStartSymbols.push_back(createBoundarySymbol(sym)); 300 else 301 seg->segmentEndSymbols.push_back(createBoundarySymbol(sym)); 302 } 303 304 void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) { 305 // Handle start/end symbols. 306 StringRef name = sym.getName(); 307 if (name.consume_front("section$start$")) 308 return handleSectionBoundarySymbol(sym, name, Boundary::Start); 309 if (name.consume_front("section$end$")) 310 return handleSectionBoundarySymbol(sym, name, Boundary::End); 311 if (name.consume_front("segment$start$")) 312 return handleSegmentBoundarySymbol(sym, name, Boundary::Start); 313 if (name.consume_front("segment$end$")) 314 return handleSegmentBoundarySymbol(sym, name, Boundary::End); 315 316 // Handle -U. 317 if (config->explicitDynamicLookups.count(sym.getName())) { 318 symtab->addDynamicLookup(sym.getName()); 319 return; 320 } 321 322 // Handle -undefined. 323 auto message = [source, &sym]() { 324 std::string message = "undefined symbol"; 325 if (config->archMultiple) 326 message += (" for arch " + getArchitectureName(config->arch())).str(); 327 message += ": " + toString(sym); 328 if (!source.empty()) 329 message += "\n>>> referenced by " + source.str(); 330 else 331 message += "\n>>> referenced by " + toString(sym.getFile()); 332 return message; 333 }; 334 switch (config->undefinedSymbolTreatment) { 335 case UndefinedSymbolTreatment::error: 336 error(message()); 337 break; 338 case UndefinedSymbolTreatment::warning: 339 warn(message()); 340 LLVM_FALLTHROUGH; 341 case UndefinedSymbolTreatment::dynamic_lookup: 342 case UndefinedSymbolTreatment::suppress: 343 symtab->addDynamicLookup(sym.getName()); 344 break; 345 case UndefinedSymbolTreatment::unknown: 346 llvm_unreachable("unknown -undefined TREATMENT"); 347 } 348 } 349 350 std::unique_ptr<SymbolTable> macho::symtab; 351