blob: 4fe455a2247d774dc3310545f6ad0fd53cffc67e [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);
Sam Clegga688a422019-03-13 21:29:20 +000040 else if (auto *F = dyn_cast<SharedFile>(File))
41 SharedFiles.push_back(F);
Sam Cleggc94d3932017-11-17 18:14:09 +000042}
43
Sam Cleggc729c1b2018-05-30 18:07:52 +000044// This function is where all the optimizations of link-time
45// optimization happens. When LTO is in use, some input files are
46// not in native object file format but in the LLVM bitcode format.
47// This function compiles bitcode files into a few big native files
48// using LLVM functions and replaces bitcode symbols with the results.
49// Because all bitcode files that the program consists of are passed
50// to the compiler at once, it can do whole-program optimization.
51void SymbolTable::addCombinedLTOObject() {
52 if (BitcodeFiles.empty())
53 return;
54
55 // Compile bitcode files and replace bitcode symbols.
56 LTO.reset(new BitcodeCompiler);
57 for (BitcodeFile *F : BitcodeFiles)
58 LTO->add(*F);
59
60 for (StringRef Filename : LTO->compile()) {
61 auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
62 Obj->parse();
63 ObjectFiles.push_back(Obj);
64 }
65}
66
Sam Cleggc94d3932017-11-17 18:14:09 +000067void SymbolTable::reportRemainingUndefines() {
Sam Clegg74fe0ba2017-12-07 01:51:24 +000068 for (Symbol *Sym : SymVector) {
Sam Cleggc729c1b2018-05-30 18:07:52 +000069 if (!Sym->isUndefined() || Sym->isWeak())
70 continue;
71 if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
72 continue;
73 if (!Sym->IsUsedInRegularObj)
74 continue;
Sam Clegg47e2b6b2018-08-04 00:04:06 +000075 error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
Sam Cleggc94d3932017-11-17 18:14:09 +000076 }
Sam Cleggc94d3932017-11-17 18:14:09 +000077}
78
79Symbol *SymbolTable::find(StringRef Name) {
Sam Clegg1f3f7742019-02-06 02:35:18 +000080 auto It = SymMap.find(CachedHashStringRef(Name));
81 if (It == SymMap.end() || It->second == -1)
82 return nullptr;
83 return SymVector[It->second];
84}
85
Sam Clegg6540e572019-02-20 23:19:31 +000086void SymbolTable::replace(StringRef Name, Symbol* Sym) {
87 auto It = SymMap.find(CachedHashStringRef(Name));
88 SymVector[It->second] = Sym;
89}
90
Sam Clegg1f3f7742019-02-06 02:35:18 +000091std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
92 bool Trace = false;
93 auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
94 int &SymIndex = P.first->second;
95 bool IsNew = P.second;
96 if (SymIndex == -1) {
97 SymIndex = SymVector.size();
98 Trace = true;
99 IsNew = true;
100 }
101
102 if (!IsNew)
103 return {SymVector[SymIndex], false};
104
105 Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
106 Sym->IsUsedInRegularObj = false;
107 Sym->Traced = Trace;
108 SymVector.emplace_back(Sym);
109 return {Sym, true};
Sam Cleggc94d3932017-11-17 18:14:09 +0000110}
111
Sam Clegg230dc112019-02-07 22:42:16 +0000112std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
113 const InputFile *File) {
Sam Clegg1f3f7742019-02-06 02:35:18 +0000114 Symbol *S;
115 bool WasInserted;
116 std::tie(S, WasInserted) = insertName(Name);
117
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000118 if (!File || File->kind() == InputFile::ObjectKind)
Sam Clegg1f3f7742019-02-06 02:35:18 +0000119 S->IsUsedInRegularObj = true;
120
121 return {S, WasInserted};
Sam Cleggc94d3932017-11-17 18:14:09 +0000122}
123
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000124static void reportTypeError(const Symbol *Existing, const InputFile *File,
Sam Clegg3876d89a2018-05-14 22:42:33 +0000125 llvm::wasm::WasmSymbolType Type) {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000126 error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
127 toString(Existing->getWasmType()) + " in " +
Sam Clegg3876d89a2018-05-14 22:42:33 +0000128 toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
129 " in " + toString(File));
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000130}
131
Heejin Ahn6f4286f2018-11-19 23:31:28 +0000132// Check the type of new symbol matches that of the symbol is replacing.
Sam Clegg6540e572019-02-20 23:19:31 +0000133// Returns true if the function types match, false is there is a singature
134// mismatch.
Benjamin Kramerba2ea932019-03-28 17:18:42 +0000135static bool signatureMatches(FunctionSymbol *Existing,
136 const WasmSignature *NewSig) {
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000137 if (!NewSig)
Sam Clegg6540e572019-02-20 23:19:31 +0000138 return true;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000139
Sam Clegg6540e572019-02-20 23:19:31 +0000140 const WasmSignature *OldSig = Existing->Signature;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000141 if (!OldSig) {
Sam Clegg6540e572019-02-20 23:19:31 +0000142 Existing->Signature = NewSig;
143 return true;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000144 }
145
Sam Clegg6540e572019-02-20 23:19:31 +0000146 return *NewSig == *OldSig;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000147}
148
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000149static void checkGlobalType(const Symbol *Existing, const InputFile *File,
150 const WasmGlobalType *NewType) {
151 if (!isa<GlobalSymbol>(Existing)) {
Sam Clegg3876d89a2018-05-14 22:42:33 +0000152 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
Sam Cleggb8621592017-11-30 01:40:08 +0000153 return;
154 }
155
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000156 const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
157 if (*NewType != *OldType) {
158 error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
159 toString(*OldType) + " in " + toString(Existing->getFile()) +
160 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
Sam Clegg93102972018-02-23 05:08:53 +0000161 }
Sam Clegg24b3dcd2018-01-28 19:57:01 +0000162}
163
Heejin Ahne915a712018-12-08 06:17:43 +0000164static void checkEventType(const Symbol *Existing, const InputFile *File,
165 const WasmEventType *NewType,
166 const WasmSignature *NewSig) {
167 auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
168 if (!isa<EventSymbol>(Existing)) {
169 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
170 return;
171 }
172
173 const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
174 const WasmSignature *OldSig = ExistingEvent->Signature;
175 if (NewType->Attribute != OldType->Attribute)
176 error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
177 toString(*OldType) + " in " + toString(Existing->getFile()) +
178 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
179 if (*NewSig != *OldSig)
180 warn("Event signature mismatch: " + Existing->getName() +
181 "\n>>> defined as " + toString(*OldSig) + " in " +
182 toString(Existing->getFile()) + "\n>>> defined as " +
183 toString(*NewSig) + " in " + toString(File));
184}
185
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000186static void checkDataType(const Symbol *Existing, const InputFile *File) {
187 if (!isa<DataSymbol>(Existing))
Sam Clegg3876d89a2018-05-14 22:42:33 +0000188 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000189}
190
Sam Cleggdfb0b2c2018-02-14 18:27:59 +0000191DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000192 uint32_t Flags,
193 InputFunction *Function) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000194 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000195 assert(!find(Name));
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000196 SyntheticFunctions.emplace_back(Function);
Sam Cleggd15a41542019-03-08 21:10:48 +0000197 return replaceSymbol<DefinedFunction>(insertName(Name).first, Name,
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000198 Flags, nullptr, Function);
Sam Clegg50686852018-01-12 18:35:13 +0000199}
200
Sam Clegg00245532018-02-20 23:38:27 +0000201DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
202 uint32_t Flags) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000203 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000204 assert(!find(Name));
Sam Cleggd15a41542019-03-08 21:10:48 +0000205 return replaceSymbol<DefinedData>(insertName(Name).first, Name, Flags);
Sam Cleggc94d3932017-11-17 18:14:09 +0000206}
207
Sam Clegg93102972018-02-23 05:08:53 +0000208DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
209 InputGlobal *Global) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000210 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
211 << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000212 assert(!find(Name));
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000213 SyntheticGlobals.emplace_back(Global);
Sam Cleggd15a41542019-03-08 21:10:48 +0000214 return replaceSymbol<DefinedGlobal>(insertName(Name).first, Name, Flags,
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000215 nullptr, Global);
Sam Clegg93102972018-02-23 05:08:53 +0000216}
217
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000218static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
219 uint32_t NewFlags) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000220 // If existing symbol is undefined, replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000221 if (!Existing->isDefined()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000222 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
223 << Existing->getName() << "\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000224 return true;
225 }
226
227 // Now we have two defined symbols. If the new one is weak, we can ignore it.
228 if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000229 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000230 return false;
231 }
232
233 // If the existing symbol is weak, we should replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000234 if (Existing->isWeak()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000235 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000236 return true;
237 }
238
239 // Neither symbol is week. They conflict.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000240 error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
241 toString(Existing->getFile()) + "\n>>> defined in " +
242 toString(NewFile));
Rui Ueyamac03c9042018-02-20 21:08:47 +0000243 return true;
Sam Clegg93e559b2018-02-20 18:55:06 +0000244}
245
246Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000247 InputFile *File,
248 InputFunction *Function) {
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000249 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
250 << (Function ? toString(Function->Signature) : "none")
251 << "]\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000252 Symbol *S;
253 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000254 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000255
Sam Clegg6540e572019-02-20 23:19:31 +0000256 auto Replace = [&](Symbol* Sym) {
257 // If the new defined function doesn't have signture (i.e. bitcode
258 // functions) but the old symbol does, then preserve the old signature
259 const WasmSignature *OldSig = S->getSignature();
260 auto* NewSym = replaceSymbol<DefinedFunction>(Sym, Name, Flags, File, Function);
261 if (!NewSym->Signature)
262 NewSym->Signature = OldSig;
263 };
264
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000265 if (WasInserted || S->isLazy()) {
Sam Clegg6540e572019-02-20 23:19:31 +0000266 Replace(S);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000267 return S;
268 }
269
Sam Clegg6540e572019-02-20 23:19:31 +0000270 auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
271 if (!ExistingFunction) {
272 reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
273 return S;
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000274 }
Sam Clegg6540e572019-02-20 23:19:31 +0000275
276 if (Function && !signatureMatches(ExistingFunction, &Function->Signature)) {
277 Symbol* Variant;
278 if (getFunctionVariant(S, &Function->Signature, File, &Variant))
279 // New variant, always replace
280 Replace(Variant);
281 else if (shouldReplace(S, File, Flags))
282 // Variant already exists, replace it after checking shouldReplace
283 Replace(Variant);
284
285 // This variant we found take the place in the symbol table as the primary
286 // variant.
287 replace(Name, Variant);
288 return Variant;
289 }
290
291 // Existing function with matching signature.
292 if (shouldReplace(S, File, Flags))
293 Replace(S);
294
Sam Clegg93e559b2018-02-20 18:55:06 +0000295 return S;
296}
297
Sam Clegg00245532018-02-20 23:38:27 +0000298Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000299 InputFile *File, InputSegment *Segment,
Sam Clegg93102972018-02-23 05:08:53 +0000300 uint32_t Address, uint32_t Size) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000301 LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
302 << "\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000303 Symbol *S;
304 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000305 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000306
Sam Clegg6540e572019-02-20 23:19:31 +0000307 auto Replace = [&]() {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000308 replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
Sam Clegg6540e572019-02-20 23:19:31 +0000309 };
310
311 if (WasInserted || S->isLazy()) {
312 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000313 return S;
314 }
315
316 checkDataType(S, File);
317
318 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000319 Replace();
Sam Cleggc94d3932017-11-17 18:14:09 +0000320 return S;
321}
322
Sam Clegg93102972018-02-23 05:08:53 +0000323Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000324 InputFile *File, InputGlobal *Global) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000325 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000326
Sam Clegg93102972018-02-23 05:08:53 +0000327 Symbol *S;
328 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000329 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000330
Sam Clegg6540e572019-02-20 23:19:31 +0000331 auto Replace = [&]() {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000332 replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
Sam Clegg6540e572019-02-20 23:19:31 +0000333 };
334
335 if (WasInserted || S->isLazy()) {
336 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000337 return S;
338 }
339
340 checkGlobalType(S, File, &Global->getType());
341
342 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000343 Replace();
Sam Clegg93102972018-02-23 05:08:53 +0000344 return S;
345}
346
Heejin Ahne915a712018-12-08 06:17:43 +0000347Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
348 InputFile *File, InputEvent *Event) {
349 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
350
351 Symbol *S;
352 bool WasInserted;
353 std::tie(S, WasInserted) = insert(Name, File);
354
Sam Clegg6540e572019-02-20 23:19:31 +0000355 auto Replace = [&]() {
Heejin Ahne915a712018-12-08 06:17:43 +0000356 replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
Sam Clegg6540e572019-02-20 23:19:31 +0000357 };
358
359 if (WasInserted || S->isLazy()) {
360 Replace();
Heejin Ahne915a712018-12-08 06:17:43 +0000361 return S;
362 }
363
364 checkEventType(S, File, &Event->getType(), &Event->Signature);
365
366 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000367 Replace();
Heejin Ahne915a712018-12-08 06:17:43 +0000368 return S;
369}
370
Dan Gohman9b84eea2019-02-07 22:00:48 +0000371Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
372 StringRef ImportModule,
Sam Clegg7cc07532019-02-01 02:29:57 +0000373 uint32_t Flags, InputFile *File,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000374 const WasmSignature *Sig) {
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000375 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
376 " [" << (Sig ? toString(*Sig) : "none") << "]\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000377
Sam Cleggc94d3932017-11-17 18:14:09 +0000378 Symbol *S;
379 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000380 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000381
Sam Clegg6540e572019-02-20 23:19:31 +0000382 auto Replace = [&]() {
Dan Gohman9b84eea2019-02-07 22:00:48 +0000383 replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
384 File, Sig);
Sam Clegg6540e572019-02-20 23:19:31 +0000385 };
386
387 if (WasInserted)
388 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000389 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000390 Lazy->fetch();
Sam Clegg6540e572019-02-20 23:19:31 +0000391 else {
392 auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
393 if (!ExistingFunction) {
394 reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
395 return S;
396 }
397 if (!signatureMatches(ExistingFunction, Sig))
398 if (getFunctionVariant(S, Sig, File, &S))
399 Replace();
400 }
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000401
Sam Cleggc94d3932017-11-17 18:14:09 +0000402 return S;
403}
404
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000405Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
406 InputFile *File) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000407 LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000408
409 Symbol *S;
410 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000411 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggf989a922018-07-17 19:15:02 +0000412
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000413 if (WasInserted)
414 replaceSymbol<UndefinedData>(S, Name, Flags, File);
415 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000416 Lazy->fetch();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000417 else if (S->isDefined())
418 checkDataType(S, File);
419 return S;
420}
421
Dan Gohman9b84eea2019-02-07 22:00:48 +0000422Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName,
423 StringRef ImportModule, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000424 InputFile *File,
425 const WasmGlobalType *Type) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000426 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000427
428 Symbol *S;
429 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000430 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000431
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000432 if (WasInserted)
Dan Gohman9b84eea2019-02-07 22:00:48 +0000433 replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags,
434 File, Type);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000435 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000436 Lazy->fetch();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000437 else if (S->isDefined())
438 checkGlobalType(S, File, Type);
439 return S;
440}
441
442void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000443 LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
Sam Cleggc94d3932017-11-17 18:14:09 +0000444 StringRef Name = Sym->getName();
Rui Ueyamac03c9042018-02-20 21:08:47 +0000445
Sam Cleggc94d3932017-11-17 18:14:09 +0000446 Symbol *S;
447 bool WasInserted;
Sam Cleggd15a41542019-03-08 21:10:48 +0000448 std::tie(S, WasInserted) = insertName(Name);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000449
Sam Cleggc94d3932017-11-17 18:14:09 +0000450 if (WasInserted) {
Sam Clegg37b4ee52019-01-29 22:26:31 +0000451 replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000452 return;
453 }
454
Sam Clegg37b4ee52019-01-29 22:26:31 +0000455 if (!S->isUndefined())
456 return;
457
458 // The existing symbol is undefined, load a new one from the archive,
459 // unless the the existing symbol is weak in which case replace the undefined
460 // symbols with a LazySymbol.
461 if (S->isWeak()) {
462 const WasmSignature *OldSig = nullptr;
463 // In the case of an UndefinedFunction we need to preserve the expected
464 // signature.
465 if (auto *F = dyn_cast<UndefinedFunction>(S))
466 OldSig = F->Signature;
467 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
468 auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
469 File, *Sym);
470 NewSym->Signature = OldSig;
471 return;
Sam Cleggc94d3932017-11-17 18:14:09 +0000472 }
Sam Clegg37b4ee52019-01-29 22:26:31 +0000473
474 LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
475 File->addMember(Sym);
Sam Cleggc94d3932017-11-17 18:14:09 +0000476}
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000477
Nicholas Wilsonc4d9aa12018-03-14 15:45:11 +0000478bool SymbolTable::addComdat(StringRef Name) {
479 return Comdats.insert(CachedHashStringRef(Name)).second;
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000480}
Sam Clegg1f3f7742019-02-06 02:35:18 +0000481
Sam Clegg6540e572019-02-20 23:19:31 +0000482// The new signature doesn't match. Create a variant to the symbol with the
483// signature encoded in the name and return that instead. These symbols are
484// then unified later in handleSymbolVariants.
485bool SymbolTable::getFunctionVariant(Symbol* Sym, const WasmSignature *Sig,
486 const InputFile *File, Symbol **Out) {
Richard Trieu14bab092019-02-21 00:36:14 +0000487 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << Sym->getName() << " -> "
Sam Clegg6540e572019-02-20 23:19:31 +0000488 << " " << toString(*Sig) << "\n");
489 Symbol *Variant = nullptr;
490
491 // Linear search through symbol variants. Should never be more than two
492 // or three entries here.
493 auto &Variants = SymVariants[CachedHashStringRef(Sym->getName())];
494 if (Variants.size() == 0)
495 Variants.push_back(Sym);
496
497 for (Symbol* V : Variants) {
498 if (*V->getSignature() == *Sig) {
499 Variant = V;
500 break;
501 }
502 }
503
504 bool WasAdded = !Variant;
505 if (WasAdded) {
506 // Create a new variant;
507 LLVM_DEBUG(dbgs() << "added new variant\n");
508 Variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
509 Variants.push_back(Variant);
510 } else {
511 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*Variant) << "\n");
512 assert(*Variant->getSignature() == *Sig);
513 }
514
515 *Out = Variant;
516 return WasAdded;
517}
518
Sam Clegg1f3f7742019-02-06 02:35:18 +0000519// Set a flag for --trace-symbol so that we can print out a log message
520// if a new symbol with the same name is inserted into the symbol table.
521void SymbolTable::trace(StringRef Name) {
522 SymMap.insert({CachedHashStringRef(Name), -1});
523}
Sam Clegg230dc112019-02-07 22:42:16 +0000524
525static const uint8_t UnreachableFn[] = {
526 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
527 0x00 /* opcode unreachable */, 0x0b /* opcode end */
528};
529
530// Replace the given symbol body with an unreachable function.
531// This is used by handleWeakUndefines in order to generate a callable
Sam Clegg6540e572019-02-20 23:19:31 +0000532// equivalent of an undefined function and also handleSymbolVariants for
533// undefined functions that don't match the signature of the definition.
Sam Clegg230dc112019-02-07 22:42:16 +0000534InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym,
535 const WasmSignature &Sig,
536 StringRef DebugName) {
537 auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
538 Func->setBody(UnreachableFn);
539 SyntheticFunctions.emplace_back(Func);
Sam Clegg6540e572019-02-20 23:19:31 +0000540 replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr,
541 Func);
Sam Clegg230dc112019-02-07 22:42:16 +0000542 return Func;
543}
544
545// For weak undefined functions, there may be "call" instructions that reference
546// the symbol. In this case, we need to synthesise a dummy/stub function that
547// will abort at runtime, so that relocations can still provided an operand to
548// the call instruction that passes Wasm validation.
549void SymbolTable::handleWeakUndefines() {
550 for (Symbol *Sym : getSymbols()) {
551 if (!Sym->isUndefWeak())
552 continue;
553
Sam Clegg6540e572019-02-20 23:19:31 +0000554 const WasmSignature *Sig = Sym->getSignature();
555 if (!Sig) {
Sam Clegg230dc112019-02-07 22:42:16 +0000556 // It is possible for undefined functions not to have a signature (eg. if
557 // added via "--undefined"), but weak undefined ones do have a signature.
Sam Clegg6540e572019-02-20 23:19:31 +0000558 // Lazy symbols may not be functions and therefore Sig can still be null
559 // in some circumstantce.
560 assert(!isa<FunctionSymbol>(Sym));
Sam Clegg230dc112019-02-07 22:42:16 +0000561 continue;
Sam Clegg6540e572019-02-20 23:19:31 +0000562 }
Sam Clegg230dc112019-02-07 22:42:16 +0000563
564 // Add a synthetic dummy for weak undefined functions. These dummies will
565 // be GC'd if not used as the target of any "call" instructions.
566 StringRef DebugName = Saver.save("undefined:" + toString(*Sym));
567 InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName);
568 // Ensure it compares equal to the null pointer, and so that table relocs
569 // don't pull in the stub body (only call-operand relocs should do that).
570 Func->setTableIndex(0);
571 // Hide our dummy to prevent export.
572 Sym->setHidden(true);
573 }
574}
Sam Clegg6540e572019-02-20 23:19:31 +0000575
576static void reportFunctionSignatureMismatch(StringRef SymName,
577 FunctionSymbol *A,
578 FunctionSymbol *B, bool Error) {
579 std::string msg = ("function signature mismatch: " + SymName +
580 "\n>>> defined as " + toString(*A->Signature) + " in " +
581 toString(A->getFile()) + "\n>>> defined as " +
582 toString(*B->Signature) + " in " + toString(B->getFile()))
583 .str();
584 if (Error)
585 error(msg);
586 else
587 warn(msg);
588}
589
590// Remove any variant symbols that were created due to function signature
591// mismatches.
592void SymbolTable::handleSymbolVariants() {
593 for (auto Pair : SymVariants) {
594 // Push the initial symbol onto the list of variants.
595 StringRef SymName = Pair.first.val();
596 std::vector<Symbol *> &Variants = Pair.second;
597
598#ifndef NDEBUG
Sam Cleggf8d736f2019-02-21 01:33:26 +0000599 LLVM_DEBUG(dbgs() << "symbol with (" << Variants.size()
600 << ") variants: " << SymName << "\n");
Sam Clegg6540e572019-02-20 23:19:31 +0000601 for (auto *S: Variants) {
602 auto *F = cast<FunctionSymbol>(S);
Sam Cleggf8d736f2019-02-21 01:33:26 +0000603 LLVM_DEBUG(dbgs() << " variant: " + F->getName() << " "
604 << toString(*F->Signature) << "\n");
Sam Clegg6540e572019-02-20 23:19:31 +0000605 }
606#endif
607
608 // Find the one definition.
609 DefinedFunction *Defined = nullptr;
610 for (auto *Symbol : Variants) {
611 if (auto F = dyn_cast<DefinedFunction>(Symbol)) {
612 Defined = F;
613 break;
614 }
615 }
616
617 // If there are no definitions, and the undefined symbols disagree on
618 // the signature, there is not we can do since we don't know which one
619 // to use as the signature on the import.
620 if (!Defined) {
621 reportFunctionSignatureMismatch(SymName,
622 cast<FunctionSymbol>(Variants[0]),
623 cast<FunctionSymbol>(Variants[1]), true);
624 return;
625 }
626
627 for (auto *Symbol : Variants) {
628 if (Symbol != Defined) {
629 auto *F = cast<FunctionSymbol>(Symbol);
630 reportFunctionSignatureMismatch(SymName, F, Defined, false);
631 StringRef DebugName = Saver.save("unreachable:" + toString(*F));
632 replaceWithUnreachable(F, *F->Signature, DebugName);
633 }
634 }
635 }
636}