blob: 35ac2c5a6da92fd8ac672405cfd66745c7a0f9e3 [file] [log] [blame]
Sam Cleggc94d3932017-11-17 18:14:09 +00001//===- SymbolTable.cpp ----------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Sam Cleggc94d3932017-11-17 18:14:09 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "SymbolTable.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000010#include "Config.h"
Sam Clegg5fa274b2018-01-10 01:13:34 +000011#include "InputChunks.h"
Heejin Ahne915a712018-12-08 06:17:43 +000012#include "InputEvent.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 Clegg45218f42018-11-27 01:08:16 +000023using namespace llvm::object;
Sam Cleggc94d3932017-11-17 18:14:09 +000024using namespace lld;
25using namespace lld::wasm;
26
27SymbolTable *lld::wasm::Symtab;
28
29void SymbolTable::addFile(InputFile *File) {
30 log("Processing: " + toString(File));
Sam Clegg1f3f7742019-02-06 02:35:18 +000031 if (Config->Trace)
32 message(toString(File));
Sam Cleggc94d3932017-11-17 18:14:09 +000033 File->parse();
34
Sam Cleggc729c1b2018-05-30 18:07:52 +000035 // LLVM bitcode file
36 if (auto *F = dyn_cast<BitcodeFile>(File))
37 BitcodeFiles.push_back(F);
38 else if (auto *F = dyn_cast<ObjFile>(File))
Sam Cleggc94d3932017-11-17 18:14:09 +000039 ObjectFiles.push_back(F);
40}
41
Sam Cleggc729c1b2018-05-30 18:07:52 +000042// This function is where all the optimizations of link-time
43// optimization happens. When LTO is in use, some input files are
44// not in native object file format but in the LLVM bitcode format.
45// This function compiles bitcode files into a few big native files
46// using LLVM functions and replaces bitcode symbols with the results.
47// Because all bitcode files that the program consists of are passed
48// to the compiler at once, it can do whole-program optimization.
49void SymbolTable::addCombinedLTOObject() {
50 if (BitcodeFiles.empty())
51 return;
52
53 // Compile bitcode files and replace bitcode symbols.
54 LTO.reset(new BitcodeCompiler);
55 for (BitcodeFile *F : BitcodeFiles)
56 LTO->add(*F);
57
58 for (StringRef Filename : LTO->compile()) {
59 auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
60 Obj->parse();
61 ObjectFiles.push_back(Obj);
62 }
63}
64
Sam Cleggc94d3932017-11-17 18:14:09 +000065void SymbolTable::reportRemainingUndefines() {
Sam Clegg74fe0ba2017-12-07 01:51:24 +000066 for (Symbol *Sym : SymVector) {
Sam Cleggc729c1b2018-05-30 18:07:52 +000067 if (!Sym->isUndefined() || Sym->isWeak())
68 continue;
69 if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
70 continue;
71 if (!Sym->IsUsedInRegularObj)
72 continue;
Sam Clegg47e2b6b2018-08-04 00:04:06 +000073 error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
Sam Cleggc94d3932017-11-17 18:14:09 +000074 }
Sam Cleggc94d3932017-11-17 18:14:09 +000075}
76
77Symbol *SymbolTable::find(StringRef Name) {
Sam Clegg1f3f7742019-02-06 02:35:18 +000078 auto It = SymMap.find(CachedHashStringRef(Name));
79 if (It == SymMap.end() || It->second == -1)
80 return nullptr;
81 return SymVector[It->second];
82}
83
84std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
85 bool Trace = false;
86 auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
87 int &SymIndex = P.first->second;
88 bool IsNew = P.second;
89 if (SymIndex == -1) {
90 SymIndex = SymVector.size();
91 Trace = true;
92 IsNew = true;
93 }
94
95 if (!IsNew)
96 return {SymVector[SymIndex], false};
97
98 Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
99 Sym->IsUsedInRegularObj = false;
100 Sym->Traced = Trace;
101 SymVector.emplace_back(Sym);
102 return {Sym, true};
Sam Cleggc94d3932017-11-17 18:14:09 +0000103}
104
Sam Clegg230dc112019-02-07 22:42:16 +0000105std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
106 const InputFile *File) {
Sam Clegg1f3f7742019-02-06 02:35:18 +0000107 Symbol *S;
108 bool WasInserted;
109 std::tie(S, WasInserted) = insertName(Name);
110
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000111 if (!File || File->kind() == InputFile::ObjectKind)
Sam Clegg1f3f7742019-02-06 02:35:18 +0000112 S->IsUsedInRegularObj = true;
113
114 return {S, WasInserted};
Sam Cleggc94d3932017-11-17 18:14:09 +0000115}
116
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000117static void reportTypeError(const Symbol *Existing, const InputFile *File,
Sam Clegg3876d89a2018-05-14 22:42:33 +0000118 llvm::wasm::WasmSymbolType Type) {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000119 error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
120 toString(Existing->getWasmType()) + " in " +
Sam Clegg3876d89a2018-05-14 22:42:33 +0000121 toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
122 " in " + toString(File));
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000123}
124
Heejin Ahn6f4286f2018-11-19 23:31:28 +0000125// Check the type of new symbol matches that of the symbol is replacing.
126// For functions this can also involve verifying that the signatures match.
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000127static void checkFunctionType(Symbol *Existing, const InputFile *File,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000128 const WasmSignature *NewSig) {
Sam Clegg65d63802018-05-14 23:01:16 +0000129 auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
130 if (!ExistingFunction) {
Sam Clegg3876d89a2018-05-14 22:42:33 +0000131 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000132 return;
133 }
134
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000135 if (!NewSig)
136 return;
137
Heejin Ahne915a712018-12-08 06:17:43 +0000138 const WasmSignature *OldSig = ExistingFunction->Signature;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000139 if (!OldSig) {
Heejin Ahne915a712018-12-08 06:17:43 +0000140 ExistingFunction->Signature = NewSig;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000141 return;
142 }
143
144 if (*NewSig != *OldSig)
Sam Cleggffd0aaf2018-06-22 15:13:10 +0000145 warn("function signature mismatch: " + Existing->getName() +
146 "\n>>> defined as " + toString(*OldSig) + " in " +
147 toString(Existing->getFile()) + "\n>>> defined as " +
148 toString(*NewSig) + " in " + toString(File));
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000149}
150
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000151static void checkGlobalType(const Symbol *Existing, const InputFile *File,
152 const WasmGlobalType *NewType) {
153 if (!isa<GlobalSymbol>(Existing)) {
Sam Clegg3876d89a2018-05-14 22:42:33 +0000154 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
Sam Cleggb8621592017-11-30 01:40:08 +0000155 return;
156 }
157
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000158 const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
159 if (*NewType != *OldType) {
160 error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
161 toString(*OldType) + " in " + toString(Existing->getFile()) +
162 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
Sam Clegg93102972018-02-23 05:08:53 +0000163 }
Sam Clegg24b3dcd2018-01-28 19:57:01 +0000164}
165
Heejin Ahne915a712018-12-08 06:17:43 +0000166static void checkEventType(const Symbol *Existing, const InputFile *File,
167 const WasmEventType *NewType,
168 const WasmSignature *NewSig) {
169 auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
170 if (!isa<EventSymbol>(Existing)) {
171 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
172 return;
173 }
174
175 const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
176 const WasmSignature *OldSig = ExistingEvent->Signature;
177 if (NewType->Attribute != OldType->Attribute)
178 error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
179 toString(*OldType) + " in " + toString(Existing->getFile()) +
180 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
181 if (*NewSig != *OldSig)
182 warn("Event signature mismatch: " + Existing->getName() +
183 "\n>>> defined as " + toString(*OldSig) + " in " +
184 toString(Existing->getFile()) + "\n>>> defined as " +
185 toString(*NewSig) + " in " + toString(File));
186}
187
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000188static void checkDataType(const Symbol *Existing, const InputFile *File) {
189 if (!isa<DataSymbol>(Existing))
Sam Clegg3876d89a2018-05-14 22:42:33 +0000190 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000191}
192
Sam Cleggdfb0b2c2018-02-14 18:27:59 +0000193DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000194 uint32_t Flags,
195 InputFunction *Function) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000196 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000197 assert(!find(Name));
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000198 SyntheticFunctions.emplace_back(Function);
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000199 return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name,
200 Flags, nullptr, Function);
Sam Clegg50686852018-01-12 18:35:13 +0000201}
202
Sam Clegg00245532018-02-20 23:38:27 +0000203DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
204 uint32_t Flags) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000205 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000206 assert(!find(Name));
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000207 return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags);
Sam Cleggc94d3932017-11-17 18:14:09 +0000208}
209
Sam Clegg93102972018-02-23 05:08:53 +0000210DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
211 InputGlobal *Global) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000212 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
213 << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000214 assert(!find(Name));
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000215 SyntheticGlobals.emplace_back(Global);
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000216 return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags,
217 nullptr, Global);
Sam Clegg93102972018-02-23 05:08:53 +0000218}
219
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000220static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
221 uint32_t NewFlags) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000222 // If existing symbol is undefined, replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000223 if (!Existing->isDefined()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000224 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
225 << Existing->getName() << "\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000226 return true;
227 }
228
229 // Now we have two defined symbols. If the new one is weak, we can ignore it.
230 if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000231 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000232 return false;
233 }
234
235 // If the existing symbol is weak, we should replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000236 if (Existing->isWeak()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000237 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000238 return true;
239 }
240
241 // Neither symbol is week. They conflict.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000242 error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
243 toString(Existing->getFile()) + "\n>>> defined in " +
244 toString(NewFile));
Rui Ueyamac03c9042018-02-20 21:08:47 +0000245 return true;
Sam Clegg93e559b2018-02-20 18:55:06 +0000246}
247
248Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000249 InputFile *File,
250 InputFunction *Function) {
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000251 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
252 << (Function ? toString(Function->Signature) : "none")
253 << "]\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000254 Symbol *S;
255 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000256 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000257
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000258 if (WasInserted || S->isLazy()) {
259 replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
260 return S;
261 }
262
Sam Cleggc729c1b2018-05-30 18:07:52 +0000263 if (Function)
264 checkFunctionType(S, File, &Function->Signature);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000265
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000266 if (shouldReplace(S, File, Flags)) {
267 // If the new defined function doesn't have signture (i.e. bitcode
Sam Clegg37b4ee52019-01-29 22:26:31 +0000268 // functions) but the old symbol does then preserve the old signature
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000269 const WasmSignature *OldSig = nullptr;
270 if (auto* F = dyn_cast<FunctionSymbol>(S))
Heejin Ahne915a712018-12-08 06:17:43 +0000271 OldSig = F->Signature;
Sam Clegg37b4ee52019-01-29 22:26:31 +0000272 if (auto *L = dyn_cast<LazySymbol>(S))
273 OldSig = L->Signature;
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000274 auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
Heejin Ahne915a712018-12-08 06:17:43 +0000275 if (!NewSym->Signature)
276 NewSym->Signature = OldSig;
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000277 }
Sam Clegg93e559b2018-02-20 18:55:06 +0000278 return S;
279}
280
Sam Clegg00245532018-02-20 23:38:27 +0000281Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000282 InputFile *File, InputSegment *Segment,
Sam Clegg93102972018-02-23 05:08:53 +0000283 uint32_t Address, uint32_t Size) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000284 LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
285 << "\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000286 Symbol *S;
287 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000288 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000289
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000290 if (WasInserted || S->isLazy()) {
291 replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
292 return S;
293 }
294
295 checkDataType(S, File);
296
297 if (shouldReplace(S, File, Flags))
298 replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
Sam Cleggc94d3932017-11-17 18:14:09 +0000299 return S;
300}
301
Sam Clegg93102972018-02-23 05:08:53 +0000302Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000303 InputFile *File, InputGlobal *Global) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000304 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000305
Sam Clegg93102972018-02-23 05:08:53 +0000306 Symbol *S;
307 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000308 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000309
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000310 if (WasInserted || S->isLazy()) {
311 replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
312 return S;
313 }
314
315 checkGlobalType(S, File, &Global->getType());
316
317 if (shouldReplace(S, File, Flags))
318 replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
Sam Clegg93102972018-02-23 05:08:53 +0000319 return S;
320}
321
Heejin Ahne915a712018-12-08 06:17:43 +0000322Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
323 InputFile *File, InputEvent *Event) {
324 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
325
326 Symbol *S;
327 bool WasInserted;
328 std::tie(S, WasInserted) = insert(Name, File);
329
330 if (WasInserted || S->isLazy()) {
331 replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
332 return S;
333 }
334
335 checkEventType(S, File, &Event->getType(), &Event->Signature);
336
337 if (shouldReplace(S, File, Flags))
338 replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
339 return S;
340}
341
Dan Gohman9b84eea2019-02-07 22:00:48 +0000342Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
343 StringRef ImportModule,
Sam Clegg7cc07532019-02-01 02:29:57 +0000344 uint32_t Flags, InputFile *File,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000345 const WasmSignature *Sig) {
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000346 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
347 " [" << (Sig ? toString(*Sig) : "none") << "]\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000348
Sam Cleggc94d3932017-11-17 18:14:09 +0000349 Symbol *S;
350 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000351 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000352
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000353 if (WasInserted)
Dan Gohman9b84eea2019-02-07 22:00:48 +0000354 replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
355 File, Sig);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000356 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000357 Lazy->fetch();
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000358 else
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000359 checkFunctionType(S, File, Sig);
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000360
Sam Cleggc94d3932017-11-17 18:14:09 +0000361 return S;
362}
363
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000364Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
365 InputFile *File) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000366 LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000367
368 Symbol *S;
369 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000370 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggf989a922018-07-17 19:15:02 +0000371
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000372 if (WasInserted)
373 replaceSymbol<UndefinedData>(S, Name, Flags, File);
374 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000375 Lazy->fetch();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000376 else if (S->isDefined())
377 checkDataType(S, File);
378 return S;
379}
380
Dan Gohman9b84eea2019-02-07 22:00:48 +0000381Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName,
382 StringRef ImportModule, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000383 InputFile *File,
384 const WasmGlobalType *Type) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000385 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000386
387 Symbol *S;
388 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000389 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000390
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000391 if (WasInserted)
Dan Gohman9b84eea2019-02-07 22:00:48 +0000392 replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags,
393 File, Type);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000394 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000395 Lazy->fetch();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000396 else if (S->isDefined())
397 checkGlobalType(S, File, Type);
398 return S;
399}
400
401void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000402 LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
Sam Cleggc94d3932017-11-17 18:14:09 +0000403 StringRef Name = Sym->getName();
Rui Ueyamac03c9042018-02-20 21:08:47 +0000404
Sam Cleggc94d3932017-11-17 18:14:09 +0000405 Symbol *S;
406 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000407 std::tie(S, WasInserted) = insert(Name, nullptr);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000408
Sam Cleggc94d3932017-11-17 18:14:09 +0000409 if (WasInserted) {
Sam Clegg37b4ee52019-01-29 22:26:31 +0000410 replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000411 return;
412 }
413
Sam Clegg37b4ee52019-01-29 22:26:31 +0000414 if (!S->isUndefined())
415 return;
416
417 // The existing symbol is undefined, load a new one from the archive,
418 // unless the the existing symbol is weak in which case replace the undefined
419 // symbols with a LazySymbol.
420 if (S->isWeak()) {
421 const WasmSignature *OldSig = nullptr;
422 // In the case of an UndefinedFunction we need to preserve the expected
423 // signature.
424 if (auto *F = dyn_cast<UndefinedFunction>(S))
425 OldSig = F->Signature;
426 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
427 auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
428 File, *Sym);
429 NewSym->Signature = OldSig;
430 return;
Sam Cleggc94d3932017-11-17 18:14:09 +0000431 }
Sam Clegg37b4ee52019-01-29 22:26:31 +0000432
433 LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
434 File->addMember(Sym);
Sam Cleggc94d3932017-11-17 18:14:09 +0000435}
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000436
Nicholas Wilsonc4d9aa12018-03-14 15:45:11 +0000437bool SymbolTable::addComdat(StringRef Name) {
438 return Comdats.insert(CachedHashStringRef(Name)).second;
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000439}
Sam Clegg1f3f7742019-02-06 02:35:18 +0000440
441// Set a flag for --trace-symbol so that we can print out a log message
442// if a new symbol with the same name is inserted into the symbol table.
443void SymbolTable::trace(StringRef Name) {
444 SymMap.insert({CachedHashStringRef(Name), -1});
445}
Sam Clegg230dc112019-02-07 22:42:16 +0000446
447static const uint8_t UnreachableFn[] = {
448 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
449 0x00 /* opcode unreachable */, 0x0b /* opcode end */
450};
451
452// Replace the given symbol body with an unreachable function.
453// This is used by handleWeakUndefines in order to generate a callable
454// equivalent of an undefined function.
455InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym,
456 const WasmSignature &Sig,
457 StringRef DebugName) {
458 auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
459 Func->setBody(UnreachableFn);
460 SyntheticFunctions.emplace_back(Func);
461 replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr, Func);
462 return Func;
463}
464
465// For weak undefined functions, there may be "call" instructions that reference
466// the symbol. In this case, we need to synthesise a dummy/stub function that
467// will abort at runtime, so that relocations can still provided an operand to
468// the call instruction that passes Wasm validation.
469void SymbolTable::handleWeakUndefines() {
470 for (Symbol *Sym : getSymbols()) {
471 if (!Sym->isUndefWeak())
472 continue;
473
474 const WasmSignature *Sig = nullptr;
475
476 if (auto *FuncSym = dyn_cast<FunctionSymbol>(Sym)) {
477 // It is possible for undefined functions not to have a signature (eg. if
478 // added via "--undefined"), but weak undefined ones do have a signature.
479 assert(FuncSym->Signature);
480 Sig = FuncSym->Signature;
481 } else if (auto *LazySym = dyn_cast<LazySymbol>(Sym)) {
482 // Lazy symbols may not be functions and therefore can have a null
483 // signature.
484 Sig = LazySym->Signature;
485 }
486
487 if (!Sig)
488 continue;
489
490 // Add a synthetic dummy for weak undefined functions. These dummies will
491 // be GC'd if not used as the target of any "call" instructions.
492 StringRef DebugName = Saver.save("undefined:" + toString(*Sym));
493 InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName);
494 // Ensure it compares equal to the null pointer, and so that table relocs
495 // don't pull in the stub body (only call-operand relocs should do that).
496 Func->setTableIndex(0);
497 // Hide our dummy to prevent export.
498 Sym->setHidden(true);
499 }
500}