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   for (Symbol *Sym : SymVector) {
64     if (!Sym->isUndefined() || Sym->isWeak())
65       continue;
66     if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
67       continue;
68     if (!Sym->IsUsedInRegularObj)
69       continue;
70     error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
71   }
72 }
73 
74 Symbol *SymbolTable::find(StringRef Name) {
75   return SymMap.lookup(CachedHashStringRef(Name));
76 }
77 
78 std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
79   bool Inserted = false;
80   Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
81   if (!Sym) {
82     Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
83     Sym->IsUsedInRegularObj = false;
84     SymVector.emplace_back(Sym);
85     Inserted = true;
86   }
87   if (!File || File->kind() == InputFile::ObjectKind)
88     Sym->IsUsedInRegularObj = true;
89   return {Sym, Inserted};
90 }
91 
92 static void reportTypeError(const Symbol *Existing, const InputFile *File,
93                             llvm::wasm::WasmSymbolType Type) {
94   error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
95         toString(Existing->getWasmType()) + " in " +
96         toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
97         " in " + toString(File));
98 }
99 
100 static void checkFunctionType(Symbol *Existing, const InputFile *File,
101                               const WasmSignature *NewSig) {
102   auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
103   if (!ExistingFunction) {
104     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
105     return;
106   }
107 
108   if (!NewSig)
109     return;
110 
111   const WasmSignature *OldSig = ExistingFunction->FunctionType;
112   if (!OldSig) {
113     ExistingFunction->FunctionType = NewSig;
114     return;
115   }
116 
117   if (*NewSig != *OldSig)
118     warn("function signature mismatch: " + Existing->getName() +
119          "\n>>> defined as " + toString(*OldSig) + " in " +
120          toString(Existing->getFile()) + "\n>>> defined as " +
121          toString(*NewSig) + " in " + toString(File));
122 }
123 
124 // Check the type of new symbol matches that of the symbol is replacing.
125 // For functions this can also involve verifying that the signatures match.
126 static void checkGlobalType(const Symbol *Existing, const InputFile *File,
127                             const WasmGlobalType *NewType) {
128   if (!isa<GlobalSymbol>(Existing)) {
129     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
130     return;
131   }
132 
133   const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
134   if (*NewType != *OldType) {
135     error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
136           toString(*OldType) + " in " + toString(Existing->getFile()) +
137           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
138   }
139 }
140 
141 static void checkDataType(const Symbol *Existing, const InputFile *File) {
142   if (!isa<DataSymbol>(Existing))
143     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
144 }
145 
146 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
147                                                    uint32_t Flags,
148                                                    InputFunction *Function) {
149   LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
150   assert(!find(Name));
151   SyntheticFunctions.emplace_back(Function);
152   return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name,
153                                         Flags, nullptr, Function);
154 }
155 
156 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
157                                                  uint32_t Flags) {
158   LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
159   assert(!find(Name));
160   return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags);
161 }
162 
163 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
164                                                InputGlobal *Global) {
165   LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
166                     << "\n");
167   assert(!find(Name));
168   SyntheticGlobals.emplace_back(Global);
169   return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags,
170                                       nullptr, Global);
171 }
172 
173 static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
174                           uint32_t NewFlags) {
175   // If existing symbol is undefined, replace it.
176   if (!Existing->isDefined()) {
177     LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
178                       << Existing->getName() << "\n");
179     return true;
180   }
181 
182   // Now we have two defined symbols. If the new one is weak, we can ignore it.
183   if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
184     LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
185     return false;
186   }
187 
188   // If the existing symbol is weak, we should replace it.
189   if (Existing->isWeak()) {
190     LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
191     return true;
192   }
193 
194   // Neither symbol is week. They conflict.
195   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
196         toString(Existing->getFile()) + "\n>>> defined in " +
197         toString(NewFile));
198   return true;
199 }
200 
201 Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
202                                         InputFile *File,
203                                         InputFunction *Function) {
204   LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
205                     << (Function ? toString(Function->Signature) : "none")
206                     << "]\n");
207   Symbol *S;
208   bool WasInserted;
209   std::tie(S, WasInserted) = insert(Name, File);
210 
211   if (WasInserted || S->isLazy()) {
212     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
213     return S;
214   }
215 
216   if (Function)
217     checkFunctionType(S, File, &Function->Signature);
218 
219   if (shouldReplace(S, File, Flags)) {
220     // If the new defined function doesn't have signture (i.e. bitcode
221     // functions) but the old symbols does then preserve the old signature
222     const WasmSignature *OldSig = nullptr;
223     if (auto* F = dyn_cast<FunctionSymbol>(S))
224       OldSig = F->FunctionType;
225     auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
226     if (!NewSym->FunctionType)
227       NewSym->FunctionType = OldSig;
228   }
229   return S;
230 }
231 
232 Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
233                                     InputFile *File, InputSegment *Segment,
234                                     uint32_t Address, uint32_t Size) {
235   LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
236                     << "\n");
237   Symbol *S;
238   bool WasInserted;
239   std::tie(S, WasInserted) = insert(Name, File);
240 
241   if (WasInserted || S->isLazy()) {
242     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
243     return S;
244   }
245 
246   checkDataType(S, File);
247 
248   if (shouldReplace(S, File, Flags))
249     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
250   return S;
251 }
252 
253 Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
254                                       InputFile *File, InputGlobal *Global) {
255   LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
256 
257   Symbol *S;
258   bool WasInserted;
259   std::tie(S, WasInserted) = insert(Name, File);
260 
261   if (WasInserted || S->isLazy()) {
262     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
263     return S;
264   }
265 
266   checkGlobalType(S, File, &Global->getType());
267 
268   if (shouldReplace(S, File, Flags))
269     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
270   return S;
271 }
272 
273 Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
274                                           InputFile *File,
275                                           const WasmSignature *Sig) {
276   LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
277              " [" << (Sig ? toString(*Sig) : "none") << "]\n");
278 
279   Symbol *S;
280   bool WasInserted;
281   std::tie(S, WasInserted) = insert(Name, File);
282 
283   if (WasInserted)
284     replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
285   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
286     Lazy->fetch();
287   else
288     checkFunctionType(S, File, Sig);
289 
290   return S;
291 }
292 
293 Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
294                                       InputFile *File) {
295   LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
296 
297   Symbol *S;
298   bool WasInserted;
299   std::tie(S, WasInserted) = insert(Name, File);
300 
301   if (WasInserted)
302     replaceSymbol<UndefinedData>(S, Name, Flags, File);
303   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
304     Lazy->fetch();
305   else if (S->isDefined())
306     checkDataType(S, File);
307   return S;
308 }
309 
310 Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
311                                         InputFile *File,
312                                         const WasmGlobalType *Type) {
313   LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
314 
315   Symbol *S;
316   bool WasInserted;
317   std::tie(S, WasInserted) = insert(Name, File);
318 
319   if (WasInserted)
320     replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
321   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
322     Lazy->fetch();
323   else if (S->isDefined())
324     checkGlobalType(S, File, Type);
325   return S;
326 }
327 
328 void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
329   LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
330   StringRef Name = Sym->getName();
331 
332   Symbol *S;
333   bool WasInserted;
334   std::tie(S, WasInserted) = insert(Name, nullptr);
335 
336   if (WasInserted) {
337     replaceSymbol<LazySymbol>(S, Name, File, *Sym);
338     return;
339   }
340 
341   // If there is an existing undefined symbol, load a new one from the archive.
342   if (S->isUndefined()) {
343     LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
344     File->addMember(Sym);
345   }
346 }
347 
348 bool SymbolTable::addComdat(StringRef Name) {
349   return Comdats.insert(CachedHashStringRef(Name)).second;
350 }
351