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