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 // Symbol table is a bag of all known symbols. We put all symbols of 10 // all input files to the symbol table. The symbol table is basically 11 // a hash table with the logic to resolve symbol name conflicts using 12 // the symbol types. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "SymbolTable.h" 17 #include "Config.h" 18 #include "LinkerScript.h" 19 #include "Symbols.h" 20 #include "SyntheticSections.h" 21 #include "lld/Common/ErrorHandler.h" 22 #include "lld/Common/Memory.h" 23 #include "lld/Common/Strings.h" 24 #include "llvm/ADT/STLExtras.h" 25 26 using namespace llvm; 27 using namespace llvm::object; 28 using namespace llvm::ELF; 29 30 using namespace lld; 31 using namespace lld::elf; 32 33 SymbolTable *elf::Symtab; 34 35 // Set a flag for --trace-symbol so that we can print out a log message 36 // if a new symbol with the same name is inserted into the symbol table. 37 void SymbolTable::trace(StringRef Name) { 38 SymMap.insert({CachedHashStringRef(Name), -1}); 39 } 40 41 void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) { 42 // Swap symbols as instructed by -wrap. 43 int &Idx1 = SymMap[CachedHashStringRef(Sym->getName())]; 44 int &Idx2 = SymMap[CachedHashStringRef(Real->getName())]; 45 int &Idx3 = SymMap[CachedHashStringRef(Wrap->getName())]; 46 47 Idx2 = Idx1; 48 Idx1 = Idx3; 49 50 // Now renaming is complete. No one refers Real symbol. We could leave 51 // Real as-is, but if Real is written to the symbol table, that may 52 // contain irrelevant values. So, we copy all values from Sym to Real. 53 StringRef S = Real->getName(); 54 memcpy(Real, Sym, sizeof(SymbolUnion)); 55 Real->setName(S); 56 } 57 58 // Find an existing symbol or create a new one. 59 Symbol *SymbolTable::insert(StringRef Name) { 60 // <name>@@<version> means the symbol is the default version. In that 61 // case <name>@@<version> will be used to resolve references to <name>. 62 // 63 // Since this is a hot path, the following string search code is 64 // optimized for speed. StringRef::find(char) is much faster than 65 // StringRef::find(StringRef). 66 size_t Pos = Name.find('@'); 67 if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@') 68 Name = Name.take_front(Pos); 69 70 auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); 71 int &SymIndex = P.first->second; 72 bool IsNew = P.second; 73 bool Traced = false; 74 75 if (SymIndex == -1) { 76 SymIndex = SymVector.size(); 77 IsNew = true; 78 Traced = true; 79 } 80 81 if (!IsNew) 82 return SymVector[SymIndex]; 83 84 Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 85 SymVector.push_back(Sym); 86 87 Sym->setName(Name); 88 Sym->SymbolKind = Symbol::PlaceholderKind; 89 Sym->VersionId = Config->DefaultSymbolVersion; 90 Sym->Visibility = STV_DEFAULT; 91 Sym->IsUsedInRegularObj = false; 92 Sym->ExportDynamic = false; 93 Sym->CanInline = true; 94 Sym->Traced = Traced; 95 Sym->ScriptDefined = false; 96 return Sym; 97 } 98 99 Symbol *SymbolTable::addSymbol(const Symbol &New) { 100 Symbol *Sym = Symtab->insert(New.getName()); 101 Sym->resolve(New); 102 return Sym; 103 } 104 105 Symbol *SymbolTable::find(StringRef Name) { 106 auto It = SymMap.find(CachedHashStringRef(Name)); 107 if (It == SymMap.end()) 108 return nullptr; 109 if (It->second == -1) 110 return nullptr; 111 return SymVector[It->second]; 112 } 113 114 // Initialize DemangledSyms with a map from demangled symbols to symbol 115 // objects. Used to handle "extern C++" directive in version scripts. 116 // 117 // The map will contain all demangled symbols. That can be very large, 118 // and in LLD we generally want to avoid do anything for each symbol. 119 // Then, why are we doing this? Here's why. 120 // 121 // Users can use "extern C++ {}" directive to match against demangled 122 // C++ symbols. For example, you can write a pattern such as 123 // "llvm::*::foo(int, ?)". Obviously, there's no way to handle this 124 // other than trying to match a pattern against all demangled symbols. 125 // So, if "extern C++" feature is used, we need to demangle all known 126 // symbols. 127 StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() { 128 if (!DemangledSyms) { 129 DemangledSyms.emplace(); 130 for (Symbol *Sym : SymVector) { 131 if (!Sym->isDefined() && !Sym->isCommon()) 132 continue; 133 if (Optional<std::string> S = demangleItanium(Sym->getName())) 134 (*DemangledSyms)[*S].push_back(Sym); 135 else 136 (*DemangledSyms)[Sym->getName()].push_back(Sym); 137 } 138 } 139 return *DemangledSyms; 140 } 141 142 std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion Ver) { 143 if (Ver.IsExternCpp) 144 return getDemangledSyms().lookup(Ver.Name); 145 if (Symbol *B = find(Ver.Name)) 146 if (B->isDefined() || B->isCommon()) 147 return {B}; 148 return {}; 149 } 150 151 std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion Ver) { 152 std::vector<Symbol *> Res; 153 StringMatcher M(Ver.Name); 154 155 if (Ver.IsExternCpp) { 156 for (auto &P : getDemangledSyms()) 157 if (M.match(P.first())) 158 Res.insert(Res.end(), P.second.begin(), P.second.end()); 159 return Res; 160 } 161 162 for (Symbol *Sym : SymVector) 163 if ((Sym->isDefined() || Sym->isCommon()) && M.match(Sym->getName())) 164 Res.push_back(Sym); 165 return Res; 166 } 167 168 // If there's only one anonymous version definition in a version 169 // script file, the script does not actually define any symbol version, 170 // but just specifies symbols visibilities. 171 void SymbolTable::handleAnonymousVersion() { 172 for (SymbolVersion &Ver : Config->VersionScriptGlobals) 173 assignExactVersion(Ver, VER_NDX_GLOBAL, "global"); 174 for (SymbolVersion &Ver : Config->VersionScriptGlobals) 175 assignWildcardVersion(Ver, VER_NDX_GLOBAL); 176 for (SymbolVersion &Ver : Config->VersionScriptLocals) 177 assignExactVersion(Ver, VER_NDX_LOCAL, "local"); 178 for (SymbolVersion &Ver : Config->VersionScriptLocals) 179 assignWildcardVersion(Ver, VER_NDX_LOCAL); 180 } 181 182 // Handles -dynamic-list. 183 void SymbolTable::handleDynamicList() { 184 for (SymbolVersion &Ver : Config->DynamicList) { 185 std::vector<Symbol *> Syms; 186 if (Ver.HasWildcard) 187 Syms = findAllByVersion(Ver); 188 else 189 Syms = findByVersion(Ver); 190 191 for (Symbol *B : Syms) { 192 if (!Config->Shared) 193 B->ExportDynamic = true; 194 else if (B->includeInDynsym()) 195 B->IsPreemptible = true; 196 } 197 } 198 } 199 200 // Set symbol versions to symbols. This function handles patterns 201 // containing no wildcard characters. 202 void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, 203 StringRef VersionName) { 204 if (Ver.HasWildcard) 205 return; 206 207 // Get a list of symbols which we need to assign the version to. 208 std::vector<Symbol *> Syms = findByVersion(Ver); 209 if (Syms.empty()) { 210 if (!Config->UndefinedVersion) 211 error("version script assignment of '" + VersionName + "' to symbol '" + 212 Ver.Name + "' failed: symbol not defined"); 213 return; 214 } 215 216 // Assign the version. 217 for (Symbol *Sym : Syms) { 218 // Skip symbols containing version info because symbol versions 219 // specified by symbol names take precedence over version scripts. 220 // See parseSymbolVersion(). 221 if (Sym->getName().contains('@')) 222 continue; 223 224 if (Sym->VersionId != Config->DefaultSymbolVersion && 225 Sym->VersionId != VersionId) 226 error("duplicate symbol '" + Ver.Name + "' in version script"); 227 Sym->VersionId = VersionId; 228 } 229 } 230 231 void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { 232 if (!Ver.HasWildcard) 233 return; 234 235 // Exact matching takes precendence over fuzzy matching, 236 // so we set a version to a symbol only if no version has been assigned 237 // to the symbol. This behavior is compatible with GNU. 238 for (Symbol *B : findAllByVersion(Ver)) 239 if (B->VersionId == Config->DefaultSymbolVersion) 240 B->VersionId = VersionId; 241 } 242 243 // This function processes version scripts by updating VersionId 244 // member of symbols. 245 void SymbolTable::scanVersionScript() { 246 // Handle edge cases first. 247 handleAnonymousVersion(); 248 handleDynamicList(); 249 250 // Now we have version definitions, so we need to set version ids to symbols. 251 // Each version definition has a glob pattern, and all symbols that match 252 // with the pattern get that version. 253 254 // First, we assign versions to exact matching symbols, 255 // i.e. version definitions not containing any glob meta-characters. 256 for (VersionDefinition &V : Config->VersionDefinitions) 257 for (SymbolVersion &Ver : V.Globals) 258 assignExactVersion(Ver, V.Id, V.Name); 259 260 // Next, we assign versions to fuzzy matching symbols, 261 // i.e. version definitions containing glob meta-characters. 262 // Note that because the last match takes precedence over previous matches, 263 // we iterate over the definitions in the reverse order. 264 for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) 265 for (SymbolVersion &Ver : V.Globals) 266 assignWildcardVersion(Ver, V.Id); 267 268 // Symbol themselves might know their versions because symbols 269 // can contain versions in the form of <name>@<version>. 270 // Let them parse and update their names to exclude version suffix. 271 for (Symbol *Sym : SymVector) 272 Sym->parseSymbolVersion(); 273 } 274