1 //===- SymbolTable.cpp ----------------------------------------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "SymbolTable.h"
11 #include "Config.h"
12 #include "InputChunks.h"
13 #include "InputGlobal.h"
14 #include "WriterUtils.h"
15 #include "lld/Common/ErrorHandler.h"
16 #include "lld/Common/Memory.h"
17 #include "llvm/ADT/SetVector.h"
18 
19 #define DEBUG_TYPE "lld"
20 
21 using namespace llvm;
22 using namespace llvm::wasm;
23 using namespace llvm::object;
24 using namespace lld;
25 using namespace lld::wasm;
26 
27 SymbolTable *lld::wasm::Symtab;
28 
29 void SymbolTable::addFile(InputFile *File) {
30   log("Processing: " + toString(File));
31   File->parse();
32 
33   // LLVM bitcode file
34   if (auto *F = dyn_cast<BitcodeFile>(File))
35     BitcodeFiles.push_back(F);
36   else if (auto *F = dyn_cast<ObjFile>(File))
37     ObjectFiles.push_back(F);
38 }
39 
40 // This function is where all the optimizations of link-time
41 // optimization happens. When LTO is in use, some input files are
42 // not in native object file format but in the LLVM bitcode format.
43 // This function compiles bitcode files into a few big native files
44 // using LLVM functions and replaces bitcode symbols with the results.
45 // Because all bitcode files that the program consists of are passed
46 // to the compiler at once, it can do whole-program optimization.
47 void SymbolTable::addCombinedLTOObject() {
48   if (BitcodeFiles.empty())
49     return;
50 
51   // Compile bitcode files and replace bitcode symbols.
52   LTO.reset(new BitcodeCompiler);
53   for (BitcodeFile *F : BitcodeFiles)
54     LTO->add(*F);
55 
56   for (StringRef Filename : LTO->compile()) {
57     auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
58     Obj->parse();
59     ObjectFiles.push_back(Obj);
60   }
61 }
62 
63 void SymbolTable::reportRemainingUndefines() {
64   for (Symbol *Sym : SymVector) {
65     if (!Sym->isUndefined() || Sym->isWeak())
66       continue;
67     if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
68       continue;
69     if (!Sym->IsUsedInRegularObj)
70       continue;
71     error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
72   }
73 }
74 
75 Symbol *SymbolTable::find(StringRef Name) {
76   return SymMap.lookup(CachedHashStringRef(Name));
77 }
78 
79 std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
80   bool Inserted = false;
81   Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
82   if (!Sym) {
83     Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
84     Sym->IsUsedInRegularObj = false;
85     SymVector.emplace_back(Sym);
86     Inserted = true;
87   }
88   if (!File || File->kind() == InputFile::ObjectKind)
89     Sym->IsUsedInRegularObj = true;
90   return {Sym, Inserted};
91 }
92 
93 static void reportTypeError(const Symbol *Existing, const InputFile *File,
94                             llvm::wasm::WasmSymbolType Type) {
95   error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
96         toString(Existing->getWasmType()) + " in " +
97         toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
98         " in " + toString(File));
99 }
100 
101 // Check the type of new symbol matches that of the symbol is replacing.
102 // For functions this can also involve verifying that the signatures match.
103 static void checkFunctionType(Symbol *Existing, const InputFile *File,
104                               const WasmSignature *NewSig) {
105   auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
106   if (!ExistingFunction) {
107     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
108     return;
109   }
110 
111   if (!NewSig)
112     return;
113 
114   const WasmSignature *OldSig = ExistingFunction->FunctionType;
115   if (!OldSig) {
116     ExistingFunction->FunctionType = NewSig;
117     return;
118   }
119 
120   if (*NewSig != *OldSig)
121     warn("function signature mismatch: " + Existing->getName() +
122          "\n>>> defined as " + toString(*OldSig) + " in " +
123          toString(Existing->getFile()) + "\n>>> defined as " +
124          toString(*NewSig) + " in " + toString(File));
125 }
126 
127 static void checkGlobalType(const Symbol *Existing, const InputFile *File,
128                             const WasmGlobalType *NewType) {
129   if (!isa<GlobalSymbol>(Existing)) {
130     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
131     return;
132   }
133 
134   const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
135   if (*NewType != *OldType) {
136     error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
137           toString(*OldType) + " in " + toString(Existing->getFile()) +
138           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
139   }
140 }
141 
142 static void checkDataType(const Symbol *Existing, const InputFile *File) {
143   if (!isa<DataSymbol>(Existing))
144     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
145 }
146 
147 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
148                                                    uint32_t Flags,
149                                                    InputFunction *Function) {
150   LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
151   assert(!find(Name));
152   SyntheticFunctions.emplace_back(Function);
153   return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name,
154                                         Flags, nullptr, Function);
155 }
156 
157 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
158                                                  uint32_t Flags) {
159   LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
160   assert(!find(Name));
161   return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags);
162 }
163 
164 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
165                                                InputGlobal *Global) {
166   LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
167                     << "\n");
168   assert(!find(Name));
169   SyntheticGlobals.emplace_back(Global);
170   return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags,
171                                       nullptr, Global);
172 }
173 
174 static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
175                           uint32_t NewFlags) {
176   // If existing symbol is undefined, replace it.
177   if (!Existing->isDefined()) {
178     LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
179                       << Existing->getName() << "\n");
180     return true;
181   }
182 
183   // Now we have two defined symbols. If the new one is weak, we can ignore it.
184   if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
185     LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
186     return false;
187   }
188 
189   // If the existing symbol is weak, we should replace it.
190   if (Existing->isWeak()) {
191     LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
192     return true;
193   }
194 
195   // Neither symbol is week. They conflict.
196   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
197         toString(Existing->getFile()) + "\n>>> defined in " +
198         toString(NewFile));
199   return true;
200 }
201 
202 Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
203                                         InputFile *File,
204                                         InputFunction *Function) {
205   LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
206                     << (Function ? toString(Function->Signature) : "none")
207                     << "]\n");
208   Symbol *S;
209   bool WasInserted;
210   std::tie(S, WasInserted) = insert(Name, File);
211 
212   if (WasInserted || S->isLazy()) {
213     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
214     return S;
215   }
216 
217   if (Function)
218     checkFunctionType(S, File, &Function->Signature);
219 
220   if (shouldReplace(S, File, Flags)) {
221     // If the new defined function doesn't have signture (i.e. bitcode
222     // functions) but the old symbols does then preserve the old signature
223     const WasmSignature *OldSig = nullptr;
224     if (auto* F = dyn_cast<FunctionSymbol>(S))
225       OldSig = F->FunctionType;
226     auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
227     if (!NewSym->FunctionType)
228       NewSym->FunctionType = OldSig;
229   }
230   return S;
231 }
232 
233 Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
234                                     InputFile *File, InputSegment *Segment,
235                                     uint32_t Address, uint32_t Size) {
236   LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
237                     << "\n");
238   Symbol *S;
239   bool WasInserted;
240   std::tie(S, WasInserted) = insert(Name, File);
241 
242   if (WasInserted || S->isLazy()) {
243     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
244     return S;
245   }
246 
247   checkDataType(S, File);
248 
249   if (shouldReplace(S, File, Flags))
250     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
251   return S;
252 }
253 
254 Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
255                                       InputFile *File, InputGlobal *Global) {
256   LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
257 
258   Symbol *S;
259   bool WasInserted;
260   std::tie(S, WasInserted) = insert(Name, File);
261 
262   if (WasInserted || S->isLazy()) {
263     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
264     return S;
265   }
266 
267   checkGlobalType(S, File, &Global->getType());
268 
269   if (shouldReplace(S, File, Flags))
270     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
271   return S;
272 }
273 
274 Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
275                                           InputFile *File,
276                                           const WasmSignature *Sig) {
277   LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
278              " [" << (Sig ? toString(*Sig) : "none") << "]\n");
279 
280   Symbol *S;
281   bool WasInserted;
282   std::tie(S, WasInserted) = insert(Name, File);
283 
284   if (WasInserted)
285     replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
286   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
287     Lazy->fetch();
288   else
289     checkFunctionType(S, File, Sig);
290 
291   return S;
292 }
293 
294 Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
295                                       InputFile *File) {
296   LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
297 
298   Symbol *S;
299   bool WasInserted;
300   std::tie(S, WasInserted) = insert(Name, File);
301 
302   if (WasInserted)
303     replaceSymbol<UndefinedData>(S, Name, Flags, File);
304   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
305     Lazy->fetch();
306   else if (S->isDefined())
307     checkDataType(S, File);
308   return S;
309 }
310 
311 Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
312                                         InputFile *File,
313                                         const WasmGlobalType *Type) {
314   LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
315 
316   Symbol *S;
317   bool WasInserted;
318   std::tie(S, WasInserted) = insert(Name, File);
319 
320   if (WasInserted)
321     replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
322   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
323     Lazy->fetch();
324   else if (S->isDefined())
325     checkGlobalType(S, File, Type);
326   return S;
327 }
328 
329 void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
330   LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
331   StringRef Name = Sym->getName();
332 
333   Symbol *S;
334   bool WasInserted;
335   std::tie(S, WasInserted) = insert(Name, nullptr);
336 
337   if (WasInserted) {
338     replaceSymbol<LazySymbol>(S, Name, File, *Sym);
339     return;
340   }
341 
342   // If there is an existing undefined symbol, load a new one from the archive.
343   if (S->isUndefined()) {
344     LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
345     File->addMember(Sym);
346   }
347 }
348 
349 bool SymbolTable::addComdat(StringRef Name) {
350   return Comdats.insert(CachedHashStringRef(Name)).second;
351 }
352