blob: b9f4e6e5e3a2709022fae55939c43fbd05157456 [file] [log] [blame]
Sam Cleggc94d3932017-11-17 18:14:09 +00001//===- 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"
Sam Cleggc94d3932017-11-17 18:14:09 +000011#include "Config.h"
Sam Clegg5fa274b2018-01-10 01:13:34 +000012#include "InputChunks.h"
Sam Clegg93102972018-02-23 05:08:53 +000013#include "InputGlobal.h"
Sam Cleggb8621592017-11-30 01:40:08 +000014#include "WriterUtils.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000015#include "lld/Common/ErrorHandler.h"
Rui Ueyama2017d522017-11-28 20:39:17 +000016#include "lld/Common/Memory.h"
Rui Ueyama7d67dd12018-02-13 22:30:52 +000017#include "llvm/ADT/SetVector.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000018
19#define DEBUG_TYPE "lld"
20
21using namespace llvm;
Sam Clegg20db3812018-01-10 00:52:20 +000022using namespace llvm::wasm;
Sam Cleggc94d3932017-11-17 18:14:09 +000023using namespace lld;
24using namespace lld::wasm;
25
26SymbolTable *lld::wasm::Symtab;
27
28void SymbolTable::addFile(InputFile *File) {
29 log("Processing: " + toString(File));
30 File->parse();
31
32 if (auto *F = dyn_cast<ObjFile>(File))
33 ObjectFiles.push_back(F);
34}
35
36void SymbolTable::reportRemainingUndefines() {
Rui Ueyama7d67dd12018-02-13 22:30:52 +000037 SetVector<Symbol *> Undefs;
Sam Clegg74fe0ba2017-12-07 01:51:24 +000038 for (Symbol *Sym : SymVector) {
Sam Cleggc94d3932017-11-17 18:14:09 +000039 if (Sym->isUndefined() && !Sym->isWeak() &&
40 Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) {
41 Undefs.insert(Sym);
42 }
43 }
44
45 if (Undefs.empty())
46 return;
47
48 for (ObjFile *File : ObjectFiles)
49 for (Symbol *Sym : File->getSymbols())
50 if (Undefs.count(Sym))
51 error(toString(File) + ": undefined symbol: " + toString(*Sym));
52
53 for (Symbol *Sym : Undefs)
54 if (!Sym->getFile())
55 error("undefined symbol: " + toString(*Sym));
56}
57
58Symbol *SymbolTable::find(StringRef Name) {
Sam Clegga80d94d2017-11-27 23:16:06 +000059 auto It = SymMap.find(CachedHashStringRef(Name));
60 if (It == SymMap.end())
Sam Cleggc94d3932017-11-17 18:14:09 +000061 return nullptr;
62 return It->second;
63}
64
65std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
Sam Clegga80d94d2017-11-27 23:16:06 +000066 Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
Sam Cleggc94d3932017-11-17 18:14:09 +000067 if (Sym)
68 return {Sym, false};
Sam Cleggdfb0b2c2018-02-14 18:27:59 +000069 Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
Sam Clegg74fe0ba2017-12-07 01:51:24 +000070 SymVector.emplace_back(Sym);
Sam Cleggc94d3932017-11-17 18:14:09 +000071 return {Sym, true};
72}
73
Rui Ueyamae3498ec2018-02-28 00:09:22 +000074static void reportTypeError(const Symbol *Existing, const InputFile *File,
75 StringRef Type) {
76 error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
77 toString(Existing->getWasmType()) + " in " +
78 toString(Existing->getFile()) + "\n>>> defined as " + Type + " in " +
79 toString(File));
80}
81
82static void checkFunctionType(const Symbol *Existing, const InputFile *File,
83 const WasmSignature *NewSig) {
84 if (!isa<FunctionSymbol>(Existing)) {
85 reportTypeError(Existing, File, "Function");
86 return;
87 }
88
89 if (!Config->CheckSignatures)
90 return;
91
92 const WasmSignature *OldSig =
93 cast<FunctionSymbol>(Existing)->getFunctionType();
94 if (OldSig && *NewSig != *OldSig) {
95 error("Function type mismatch: " + Existing->getName() +
96 "\n>>> defined as " + toString(*OldSig) + " in " +
97 toString(Existing->getFile()) + "\n>>> defined as " +
98 toString(*NewSig) + " in " + toString(File));
99 }
100}
101
Sam Cleggb8621592017-11-30 01:40:08 +0000102// Check the type of new symbol matches that of the symbol is replacing.
103// For functions this can also involve verifying that the signatures match.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000104static void checkGlobalType(const Symbol *Existing, const InputFile *File,
105 const WasmGlobalType *NewType) {
106 if (!isa<GlobalSymbol>(Existing)) {
107 reportTypeError(Existing, File, "Global");
Sam Cleggb8621592017-11-30 01:40:08 +0000108 return;
109 }
110
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000111 const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
112 if (*NewType != *OldType) {
113 error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
114 toString(*OldType) + " in " + toString(Existing->getFile()) +
115 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
Sam Clegg93102972018-02-23 05:08:53 +0000116 }
Sam Clegg24b3dcd2018-01-28 19:57:01 +0000117}
118
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000119static void checkDataType(const Symbol *Existing, const InputFile *File) {
120 if (!isa<DataSymbol>(Existing))
121 reportTypeError(Existing, File, "Data");
122}
123
Sam Cleggdfb0b2c2018-02-14 18:27:59 +0000124DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
125 const WasmSignature *Type,
126 uint32_t Flags) {
Sam Clegga1892302018-02-13 20:14:26 +0000127 DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
Sam Clegg50686852018-01-12 18:35:13 +0000128 Symbol *S;
129 bool WasInserted;
130 std::tie(S, WasInserted) = insert(Name);
Sam Clegga1892302018-02-13 20:14:26 +0000131 assert(WasInserted);
Sam Cleggdfb0b2c2018-02-14 18:27:59 +0000132 return replaceSymbol<DefinedFunction>(S, Name, Flags, Type);
Sam Clegg50686852018-01-12 18:35:13 +0000133}
134
Sam Clegg00245532018-02-20 23:38:27 +0000135DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
136 uint32_t Flags) {
137 DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
Sam Cleggc94d3932017-11-17 18:14:09 +0000138 Symbol *S;
139 bool WasInserted;
140 std::tie(S, WasInserted) = insert(Name);
Sam Clegga1892302018-02-13 20:14:26 +0000141 assert(WasInserted);
Sam Clegg00245532018-02-20 23:38:27 +0000142 return replaceSymbol<DefinedData>(S, Name, Flags);
Sam Cleggc94d3932017-11-17 18:14:09 +0000143}
144
Sam Clegg93102972018-02-23 05:08:53 +0000145DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
146 InputGlobal *Global) {
147 DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global << "\n");
148 Symbol *S;
149 bool WasInserted;
150 std::tie(S, WasInserted) = insert(Name);
151 assert(WasInserted);
152 return replaceSymbol<DefinedGlobal>(S, Name, Flags, nullptr, Global);
153}
154
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000155static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
156 uint32_t NewFlags) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000157 // If existing symbol is undefined, replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000158 if (!Existing->isDefined()) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000159 DEBUG(dbgs() << "resolving existing undefined symbol: "
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000160 << Existing->getName() << "\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000161 return true;
162 }
163
164 // Now we have two defined symbols. If the new one is weak, we can ignore it.
165 if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
166 DEBUG(dbgs() << "existing symbol takes precedence\n");
167 return false;
168 }
169
170 // If the existing symbol is weak, we should replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000171 if (Existing->isWeak()) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000172 DEBUG(dbgs() << "replacing existing weak symbol\n");
173 return true;
174 }
175
176 // Neither symbol is week. They conflict.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000177 error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
178 toString(Existing->getFile()) + "\n>>> defined in " +
179 toString(NewFile));
Rui Ueyamac03c9042018-02-20 21:08:47 +0000180 return true;
Sam Clegg93e559b2018-02-20 18:55:06 +0000181}
182
183Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000184 InputFile *File,
185 InputFunction *Function) {
Sam Clegg93e559b2018-02-20 18:55:06 +0000186 DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
187 Symbol *S;
188 bool WasInserted;
189 std::tie(S, WasInserted) = insert(Name);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000190
191 if (WasInserted || S->isLazy()) {
192 replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
193 return S;
194 }
195
196 checkFunctionType(S, File, &Function->Signature);
197
198 if (shouldReplace(S, File, Flags))
199 replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
Sam Clegg93e559b2018-02-20 18:55:06 +0000200 return S;
201}
202
Sam Clegg00245532018-02-20 23:38:27 +0000203Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000204 InputFile *File, InputSegment *Segment,
Sam Clegg93102972018-02-23 05:08:53 +0000205 uint32_t Address, uint32_t Size) {
Sam Clegg00245532018-02-20 23:38:27 +0000206 DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address << "\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000207 Symbol *S;
208 bool WasInserted;
209 std::tie(S, WasInserted) = insert(Name);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000210
211 if (WasInserted || S->isLazy()) {
212 replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
213 return S;
214 }
215
216 checkDataType(S, File);
217
218 if (shouldReplace(S, File, Flags))
219 replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
Sam Cleggc94d3932017-11-17 18:14:09 +0000220 return S;
221}
222
Sam Clegg93102972018-02-23 05:08:53 +0000223Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000224 InputFile *File, InputGlobal *Global) {
Sam Clegg93102972018-02-23 05:08:53 +0000225 DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
226 Symbol *S;
227 bool WasInserted;
228 std::tie(S, WasInserted) = insert(Name);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000229
230 if (WasInserted || S->isLazy()) {
231 replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
232 return S;
233 }
234
235 checkGlobalType(S, File, &Global->getType());
236
237 if (shouldReplace(S, File, Flags))
238 replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
Sam Clegg93102972018-02-23 05:08:53 +0000239 return S;
240}
241
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000242Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
243 InputFile *File,
244 const WasmSignature *Sig) {
245 DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000246
Sam Cleggc94d3932017-11-17 18:14:09 +0000247 Symbol *S;
248 bool WasInserted;
Sam Clegg20db3812018-01-10 00:52:20 +0000249 std::tie(S, WasInserted) = insert(Name);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000250
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000251 if (WasInserted)
252 replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
253 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamac03c9042018-02-20 21:08:47 +0000254 cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol());
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000255 else if (S->isDefined())
256 checkFunctionType(S, File, Sig);
Sam Cleggc94d3932017-11-17 18:14:09 +0000257 return S;
258}
259
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000260Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
261 InputFile *File) {
262 DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
263
264 Symbol *S;
265 bool WasInserted;
266 std::tie(S, WasInserted) = insert(Name);
267
268 if (WasInserted)
269 replaceSymbol<UndefinedData>(S, Name, Flags, File);
270 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
271 cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol());
272 else if (S->isDefined())
273 checkDataType(S, File);
274 return S;
275}
276
277Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
278 InputFile *File,
279 const WasmGlobalType *Type) {
280 DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
281
282 Symbol *S;
283 bool WasInserted;
284 std::tie(S, WasInserted) = insert(Name);
285
286 if (WasInserted)
287 replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
288 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
289 cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol());
290 else if (S->isDefined())
291 checkGlobalType(S, File, Type);
292 return S;
293}
294
295void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
Sam Clegga681a112017-12-06 03:10:39 +0000296 DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
Sam Cleggc94d3932017-11-17 18:14:09 +0000297 StringRef Name = Sym->getName();
Rui Ueyamac03c9042018-02-20 21:08:47 +0000298
Sam Cleggc94d3932017-11-17 18:14:09 +0000299 Symbol *S;
300 bool WasInserted;
301 std::tie(S, WasInserted) = insert(Name);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000302
Sam Cleggc94d3932017-11-17 18:14:09 +0000303 if (WasInserted) {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000304 replaceSymbol<LazySymbol>(S, Name, File, *Sym);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000305 return;
306 }
307
308 // If there is an existing undefined symbol, load a new one from the archive.
309 if (S->isUndefined()) {
Sam Cleggc94d3932017-11-17 18:14:09 +0000310 DEBUG(dbgs() << "replacing existing undefined\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000311 File->addMember(Sym);
Sam Cleggc94d3932017-11-17 18:14:09 +0000312 }
313}
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000314
315bool SymbolTable::addComdat(StringRef Name, ObjFile *F) {
316 DEBUG(dbgs() << "addComdat: " << Name << "\n");
317 ObjFile *&File = ComdatMap[CachedHashStringRef(Name)];
318 if (File) {
319 DEBUG(dbgs() << "COMDAT already defined\n");
320 return false;
321 }
322 File = F;
323 return true;
324}
325
326ObjFile *SymbolTable::findComdat(StringRef Name) const {
327 auto It = ComdatMap.find(CachedHashStringRef(Name));
328 return It == ComdatMap.end() ? nullptr : It->second;
329}