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