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