blob: 3c1acbd2c68fd5c5addcea5a1a7e14983aa9d60b [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 +000024
Fangrui Song33c59ab2019-10-10 05:25:39 +000025namespace lld {
26namespace wasm {
27SymbolTable *symtab;
Sam Cleggc94d3932017-11-17 18:14:09 +000028
Rui Ueyama136d27a2019-07-11 05:40:30 +000029void SymbolTable::addFile(InputFile *file) {
30 log("Processing: " + toString(file));
Sam Clegga282a612019-06-05 17:50:45 +000031
32 // .a file
Rui Ueyama136d27a2019-07-11 05:40:30 +000033 if (auto *f = dyn_cast<ArchiveFile>(file)) {
34 f->parse();
Sam Clegga282a612019-06-05 17:50:45 +000035 return;
36 }
37
38 // .so file
Rui Ueyama136d27a2019-07-11 05:40:30 +000039 if (auto *f = dyn_cast<SharedFile>(file)) {
40 sharedFiles.push_back(f);
Sam Clegga282a612019-06-05 17:50:45 +000041 return;
42 }
43
Rui Ueyama136d27a2019-07-11 05:40:30 +000044 if (config->trace)
45 message(toString(file));
Sam Cleggc94d3932017-11-17 18:14:09 +000046
Sam Cleggc729c1b2018-05-30 18:07:52 +000047 // LLVM bitcode file
Rui Ueyama136d27a2019-07-11 05:40:30 +000048 if (auto *f = dyn_cast<BitcodeFile>(file)) {
49 f->parse();
50 bitcodeFiles.push_back(f);
Sam Clegga282a612019-06-05 17:50:45 +000051 return;
52 }
53
54 // Regular object file
Rui Ueyama136d27a2019-07-11 05:40:30 +000055 auto *f = cast<ObjFile>(file);
56 f->parse(false);
57 objectFiles.push_back(f);
Sam Cleggc94d3932017-11-17 18:14:09 +000058}
59
Sam Cleggc729c1b2018-05-30 18:07:52 +000060// This function is where all the optimizations of link-time
61// optimization happens. When LTO is in use, some input files are
62// not in native object file format but in the LLVM bitcode format.
63// This function compiles bitcode files into a few big native files
64// using LLVM functions and replaces bitcode symbols with the results.
65// Because all bitcode files that the program consists of are passed
66// to the compiler at once, it can do whole-program optimization.
67void SymbolTable::addCombinedLTOObject() {
Rui Ueyama136d27a2019-07-11 05:40:30 +000068 if (bitcodeFiles.empty())
Sam Cleggc729c1b2018-05-30 18:07:52 +000069 return;
70
71 // Compile bitcode files and replace bitcode symbols.
Rui Ueyama136d27a2019-07-11 05:40:30 +000072 lto.reset(new BitcodeCompiler);
73 for (BitcodeFile *f : bitcodeFiles)
74 lto->add(*f);
Sam Cleggc729c1b2018-05-30 18:07:52 +000075
Rui Ueyama136d27a2019-07-11 05:40:30 +000076 for (StringRef filename : lto->compile()) {
77 auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), "");
78 obj->parse(true);
79 objectFiles.push_back(obj);
Sam Cleggc729c1b2018-05-30 18:07:52 +000080 }
81}
82
Rui Ueyama136d27a2019-07-11 05:40:30 +000083Symbol *SymbolTable::find(StringRef name) {
84 auto it = symMap.find(CachedHashStringRef(name));
85 if (it == symMap.end() || it->second == -1)
Sam Clegg1f3f7742019-02-06 02:35:18 +000086 return nullptr;
Rui Ueyama136d27a2019-07-11 05:40:30 +000087 return symVector[it->second];
Sam Clegg1f3f7742019-02-06 02:35:18 +000088}
89
Rui Ueyama136d27a2019-07-11 05:40:30 +000090void SymbolTable::replace(StringRef name, Symbol* sym) {
91 auto it = symMap.find(CachedHashStringRef(name));
92 symVector[it->second] = sym;
Sam Clegg6540e572019-02-20 23:19:31 +000093}
94
Rui Ueyama136d27a2019-07-11 05:40:30 +000095std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
96 bool trace = false;
97 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
98 int &symIndex = p.first->second;
99 bool isNew = p.second;
100 if (symIndex == -1) {
101 symIndex = symVector.size();
102 trace = true;
103 isNew = true;
Sam Clegg1f3f7742019-02-06 02:35:18 +0000104 }
105
Rui Ueyama136d27a2019-07-11 05:40:30 +0000106 if (!isNew)
107 return {symVector[symIndex], false};
Sam Clegg1f3f7742019-02-06 02:35:18 +0000108
Rui Ueyama136d27a2019-07-11 05:40:30 +0000109 Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
110 sym->isUsedInRegularObj = false;
111 sym->canInline = true;
112 sym->traced = trace;
113 symVector.emplace_back(sym);
114 return {sym, true};
Sam Cleggc94d3932017-11-17 18:14:09 +0000115}
116
Rui Ueyama136d27a2019-07-11 05:40:30 +0000117std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
118 const InputFile *file) {
119 Symbol *s;
120 bool wasInserted;
121 std::tie(s, wasInserted) = insertName(name);
Sam Clegg1f3f7742019-02-06 02:35:18 +0000122
Rui Ueyama136d27a2019-07-11 05:40:30 +0000123 if (!file || file->kind() == InputFile::ObjectKind)
124 s->isUsedInRegularObj = true;
Sam Clegg1f3f7742019-02-06 02:35:18 +0000125
Rui Ueyama136d27a2019-07-11 05:40:30 +0000126 return {s, wasInserted};
Sam Cleggc94d3932017-11-17 18:14:09 +0000127}
128
Rui Ueyama136d27a2019-07-11 05:40:30 +0000129static void reportTypeError(const Symbol *existing, const InputFile *file,
130 llvm::wasm::WasmSymbolType type) {
131 error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " +
132 toString(existing->getWasmType()) + " in " +
133 toString(existing->getFile()) + "\n>>> defined as " + toString(type) +
134 " in " + toString(file));
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000135}
136
Heejin Ahn6f4286f2018-11-19 23:31:28 +0000137// Check the type of new symbol matches that of the symbol is replacing.
Sam Clegg6540e572019-02-20 23:19:31 +0000138// Returns true if the function types match, false is there is a singature
139// mismatch.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000140static bool signatureMatches(FunctionSymbol *existing,
141 const WasmSignature *newSig) {
142 const WasmSignature *oldSig = existing->signature;
Sam Cleggd506b0a2019-05-29 15:36:42 +0000143
144 // If either function is missing a signature (this happend for bitcode
145 // symbols) then assume they match. Any mismatch will be reported later
146 // when the LTO objects are added.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000147 if (!newSig || !oldSig)
Sam Clegg6540e572019-02-20 23:19:31 +0000148 return true;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000149
Rui Ueyama136d27a2019-07-11 05:40:30 +0000150 return *newSig == *oldSig;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000151}
152
Rui Ueyama136d27a2019-07-11 05:40:30 +0000153static void checkGlobalType(const Symbol *existing, const InputFile *file,
154 const WasmGlobalType *newType) {
155 if (!isa<GlobalSymbol>(existing)) {
156 reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL);
Sam Cleggb8621592017-11-30 01:40:08 +0000157 return;
158 }
159
Rui Ueyama136d27a2019-07-11 05:40:30 +0000160 const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType();
161 if (*newType != *oldType) {
162 error("Global type mismatch: " + existing->getName() + "\n>>> defined as " +
163 toString(*oldType) + " in " + toString(existing->getFile()) +
164 "\n>>> defined as " + toString(*newType) + " in " + toString(file));
Sam Clegg93102972018-02-23 05:08:53 +0000165 }
Sam Clegg24b3dcd2018-01-28 19:57:01 +0000166}
167
Rui Ueyama136d27a2019-07-11 05:40:30 +0000168static void checkEventType(const Symbol *existing, const InputFile *file,
169 const WasmEventType *newType,
170 const WasmSignature *newSig) {
171 auto existingEvent = dyn_cast<EventSymbol>(existing);
172 if (!isa<EventSymbol>(existing)) {
173 reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT);
Heejin Ahne915a712018-12-08 06:17:43 +0000174 return;
175 }
176
Rui Ueyama136d27a2019-07-11 05:40:30 +0000177 const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType();
178 const WasmSignature *oldSig = existingEvent->signature;
179 if (newType->Attribute != oldType->Attribute)
180 error("Event type mismatch: " + existing->getName() + "\n>>> defined as " +
181 toString(*oldType) + " in " + toString(existing->getFile()) +
182 "\n>>> defined as " + toString(*newType) + " in " + toString(file));
183 if (*newSig != *oldSig)
184 warn("Event signature mismatch: " + existing->getName() +
185 "\n>>> defined as " + toString(*oldSig) + " in " +
186 toString(existing->getFile()) + "\n>>> defined as " +
187 toString(*newSig) + " in " + toString(file));
Heejin Ahne915a712018-12-08 06:17:43 +0000188}
189
Rui Ueyama136d27a2019-07-11 05:40:30 +0000190static void checkDataType(const Symbol *existing, const InputFile *file) {
191 if (!isa<DataSymbol>(existing))
192 reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000193}
194
Rui Ueyama136d27a2019-07-11 05:40:30 +0000195DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name,
196 uint32_t flags,
197 InputFunction *function) {
198 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n");
199 assert(!find(name));
200 syntheticFunctions.emplace_back(function);
201 return replaceSymbol<DefinedFunction>(insertName(name).first, name,
202 flags, nullptr, function);
Sam Clegg50686852018-01-12 18:35:13 +0000203}
204
Sam Clegg8e8ddaa2019-06-04 16:35:23 +0000205// Adds an optional, linker generated, data symbols. The symbol will only be
Kazuaki Ishizaki7ae3d332020-01-06 10:21:05 -0800206// added if there is an undefine reference to it, or if it is explicitly
207// exported via the --export flag. Otherwise we don't add the symbol and return
208// nullptr.
Sam Cleggcaa0db12019-08-08 16:58:36 +0000209DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name,
210 uint32_t value) {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000211 Symbol *s = find(name);
212 if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0))
213 s = insertName(name).first;
214 else if (!s || s->isDefined())
Sam Clegg4bce63a2019-05-23 10:06:03 +0000215 return nullptr;
Rui Ueyama136d27a2019-07-11 05:40:30 +0000216 LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n");
Sam Cleggcaa0db12019-08-08 16:58:36 +0000217 auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN);
Rui Ueyama136d27a2019-07-11 05:40:30 +0000218 rtn->setVirtualAddress(value);
219 rtn->referenced = true;
Sam Clegg4bce63a2019-05-23 10:06:03 +0000220 return rtn;
221}
222
Rui Ueyama136d27a2019-07-11 05:40:30 +0000223DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name,
224 uint32_t flags) {
225 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n");
226 assert(!find(name));
227 return replaceSymbol<DefinedData>(insertName(name).first, name, flags);
Sam Cleggc94d3932017-11-17 18:14:09 +0000228}
229
Rui Ueyama136d27a2019-07-11 05:40:30 +0000230DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags,
231 InputGlobal *global) {
232 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global
Nicola Zaghene7245b42018-05-15 13:36:20 +0000233 << "\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000234 assert(!find(name));
235 syntheticGlobals.emplace_back(global);
236 return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags,
237 nullptr, global);
Sam Clegg93102972018-02-23 05:08:53 +0000238}
239
Rui Ueyama136d27a2019-07-11 05:40:30 +0000240static bool shouldReplace(const Symbol *existing, InputFile *newFile,
241 uint32_t newFlags) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000242 // If existing symbol is undefined, replace it.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000243 if (!existing->isDefined()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000244 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
Rui Ueyama136d27a2019-07-11 05:40:30 +0000245 << existing->getName() << "\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000246 return true;
247 }
248
249 // Now we have two defined symbols. If the new one is weak, we can ignore it.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000250 if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000251 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000252 return false;
253 }
254
255 // If the existing symbol is weak, we should replace it.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000256 if (existing->isWeak()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000257 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000258 return true;
259 }
260
261 // Neither symbol is week. They conflict.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000262 error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
263 toString(existing->getFile()) + "\n>>> defined in " +
264 toString(newFile));
Rui Ueyamac03c9042018-02-20 21:08:47 +0000265 return true;
Sam Clegg93e559b2018-02-20 18:55:06 +0000266}
267
Rui Ueyama136d27a2019-07-11 05:40:30 +0000268Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags,
269 InputFile *file,
270 InputFunction *function) {
271 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " ["
272 << (function ? toString(function->signature) : "none")
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000273 << "]\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000274 Symbol *s;
275 bool wasInserted;
276 std::tie(s, wasInserted) = insert(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000277
Rui Ueyama136d27a2019-07-11 05:40:30 +0000278 auto replaceSym = [&](Symbol *sym) {
Sam Clegg6540e572019-02-20 23:19:31 +0000279 // If the new defined function doesn't have signture (i.e. bitcode
280 // functions) but the old symbol does, then preserve the old signature
Rui Ueyama136d27a2019-07-11 05:40:30 +0000281 const WasmSignature *oldSig = s->getSignature();
282 auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function);
283 if (!newSym->signature)
284 newSym->signature = oldSig;
Sam Clegg6540e572019-02-20 23:19:31 +0000285 };
286
Rui Ueyama136d27a2019-07-11 05:40:30 +0000287 if (wasInserted || s->isLazy()) {
288 replaceSym(s);
289 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000290 }
291
Rui Ueyama136d27a2019-07-11 05:40:30 +0000292 auto existingFunction = dyn_cast<FunctionSymbol>(s);
293 if (!existingFunction) {
294 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
295 return s;
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000296 }
Sam Clegg6540e572019-02-20 23:19:31 +0000297
Rui Ueyama136d27a2019-07-11 05:40:30 +0000298 bool checkSig = true;
299 if (auto ud = dyn_cast<UndefinedFunction>(existingFunction))
300 checkSig = ud->isCalledDirectly;
Sam Clegg59f959f2019-05-24 22:45:08 +0000301
Rui Ueyama136d27a2019-07-11 05:40:30 +0000302 if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) {
303 Symbol* variant;
304 if (getFunctionVariant(s, &function->signature, file, &variant))
Sam Clegg6540e572019-02-20 23:19:31 +0000305 // New variant, always replace
Rui Ueyama136d27a2019-07-11 05:40:30 +0000306 replaceSym(variant);
307 else if (shouldReplace(s, file, flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000308 // Variant already exists, replace it after checking shouldReplace
Rui Ueyama136d27a2019-07-11 05:40:30 +0000309 replaceSym(variant);
Sam Clegg6540e572019-02-20 23:19:31 +0000310
311 // This variant we found take the place in the symbol table as the primary
312 // variant.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000313 replace(name, variant);
314 return variant;
Sam Clegg6540e572019-02-20 23:19:31 +0000315 }
316
317 // Existing function with matching signature.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000318 if (shouldReplace(s, file, flags))
319 replaceSym(s);
Sam Clegg6540e572019-02-20 23:19:31 +0000320
Rui Ueyama136d27a2019-07-11 05:40:30 +0000321 return s;
Sam Clegg93e559b2018-02-20 18:55:06 +0000322}
323
Rui Ueyama136d27a2019-07-11 05:40:30 +0000324Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags,
325 InputFile *file, InputSegment *segment,
326 uint32_t address, uint32_t size) {
327 LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address
Nicola Zaghene7245b42018-05-15 13:36:20 +0000328 << "\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000329 Symbol *s;
330 bool wasInserted;
331 std::tie(s, wasInserted) = insert(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000332
Rui Ueyama136d27a2019-07-11 05:40:30 +0000333 auto replaceSym = [&]() {
334 replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size);
Sam Clegg6540e572019-02-20 23:19:31 +0000335 };
336
Rui Ueyama136d27a2019-07-11 05:40:30 +0000337 if (wasInserted || s->isLazy()) {
338 replaceSym();
339 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000340 }
341
Rui Ueyama136d27a2019-07-11 05:40:30 +0000342 checkDataType(s, file);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000343
Rui Ueyama136d27a2019-07-11 05:40:30 +0000344 if (shouldReplace(s, file, flags))
345 replaceSym();
346 return s;
Sam Cleggc94d3932017-11-17 18:14:09 +0000347}
348
Rui Ueyama136d27a2019-07-11 05:40:30 +0000349Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags,
350 InputFile *file, InputGlobal *global) {
351 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n");
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000352
Rui Ueyama136d27a2019-07-11 05:40:30 +0000353 Symbol *s;
354 bool wasInserted;
355 std::tie(s, wasInserted) = insert(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000356
Rui Ueyama136d27a2019-07-11 05:40:30 +0000357 auto replaceSym = [&]() {
358 replaceSymbol<DefinedGlobal>(s, name, flags, file, global);
Sam Clegg6540e572019-02-20 23:19:31 +0000359 };
360
Rui Ueyama136d27a2019-07-11 05:40:30 +0000361 if (wasInserted || s->isLazy()) {
362 replaceSym();
363 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000364 }
365
Rui Ueyama136d27a2019-07-11 05:40:30 +0000366 checkGlobalType(s, file, &global->getType());
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000367
Rui Ueyama136d27a2019-07-11 05:40:30 +0000368 if (shouldReplace(s, file, flags))
369 replaceSym();
370 return s;
Sam Clegg93102972018-02-23 05:08:53 +0000371}
372
Rui Ueyama136d27a2019-07-11 05:40:30 +0000373Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags,
374 InputFile *file, InputEvent *event) {
375 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n");
Heejin Ahne915a712018-12-08 06:17:43 +0000376
Rui Ueyama136d27a2019-07-11 05:40:30 +0000377 Symbol *s;
378 bool wasInserted;
379 std::tie(s, wasInserted) = insert(name, file);
Heejin Ahne915a712018-12-08 06:17:43 +0000380
Rui Ueyama136d27a2019-07-11 05:40:30 +0000381 auto replaceSym = [&]() {
382 replaceSymbol<DefinedEvent>(s, name, flags, file, event);
Sam Clegg6540e572019-02-20 23:19:31 +0000383 };
384
Rui Ueyama136d27a2019-07-11 05:40:30 +0000385 if (wasInserted || s->isLazy()) {
386 replaceSym();
387 return s;
Heejin Ahne915a712018-12-08 06:17:43 +0000388 }
389
Rui Ueyama136d27a2019-07-11 05:40:30 +0000390 checkEventType(s, file, &event->getType(), &event->signature);
Heejin Ahne915a712018-12-08 06:17:43 +0000391
Rui Ueyama136d27a2019-07-11 05:40:30 +0000392 if (shouldReplace(s, file, flags))
393 replaceSym();
394 return s;
Heejin Ahne915a712018-12-08 06:17:43 +0000395}
396
Sam Clegg67b05582019-10-17 05:16:54 +0000397// This function get called when an undefined symbol is added, and there is
398// already an existing one in the symbols table. In this case we check that
399// custom 'import-module' and 'import-field' symbol attributes agree.
Kazuaki Ishizaki7ae3d332020-01-06 10:21:05 -0800400// With LTO these attributes are not available when the bitcode is read and only
Sam Clegg67b05582019-10-17 05:16:54 +0000401// become available when the LTO object is read. In this case we silently
402// replace the empty attributes with the valid ones.
403template <typename T>
404static void setImportAttributes(T *existing, StringRef importName,
405 StringRef importModule, InputFile *file) {
406 if (!importName.empty()) {
407 if (existing->importName.empty())
408 existing->importName = importName;
409 if (existing->importName != importName)
410 error("import name mismatch for symbol: " + toString(*existing) +
411 "\n>>> defined as " + existing->importName + " in " +
412 toString(existing->getFile()) + "\n>>> defined as " + importName +
413 " in " + toString(file));
414 }
415
416 if (!importModule.empty()) {
417 if (existing->importModule.empty())
418 existing->importModule = importModule;
419 if (existing->importModule != importModule)
420 error("import module mismatch for symbol: " + toString(*existing) +
421 "\n>>> defined as " + existing->importModule + " in " +
422 toString(existing->getFile()) + "\n>>> defined as " + importModule +
423 " in " + toString(file));
424 }
425}
426
Rui Ueyama136d27a2019-07-11 05:40:30 +0000427Symbol *SymbolTable::addUndefinedFunction(StringRef name, StringRef importName,
428 StringRef importModule,
429 uint32_t flags, InputFile *file,
430 const WasmSignature *sig,
431 bool isCalledDirectly) {
432 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " ["
433 << (sig ? toString(*sig) : "none")
434 << "] IsCalledDirectly:" << isCalledDirectly << "\n");
Sam Cleggf6f4b982019-09-23 21:28:29 +0000435 assert(flags & WASM_SYMBOL_UNDEFINED);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000436
Rui Ueyama136d27a2019-07-11 05:40:30 +0000437 Symbol *s;
438 bool wasInserted;
439 std::tie(s, wasInserted) = insert(name, file);
440 if (s->traced)
441 printTraceSymbolUndefined(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000442
Rui Ueyama136d27a2019-07-11 05:40:30 +0000443 auto replaceSym = [&]() {
444 replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags,
445 file, sig, isCalledDirectly);
Sam Clegg6540e572019-02-20 23:19:31 +0000446 };
447
Rui Ueyama136d27a2019-07-11 05:40:30 +0000448 if (wasInserted)
449 replaceSym();
450 else if (auto *lazy = dyn_cast<LazySymbol>(s))
451 lazy->fetch();
Sam Clegg6540e572019-02-20 23:19:31 +0000452 else {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000453 auto existingFunction = dyn_cast<FunctionSymbol>(s);
454 if (!existingFunction) {
455 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
456 return s;
Sam Clegg6540e572019-02-20 23:19:31 +0000457 }
Sam Clegg67b05582019-10-17 05:16:54 +0000458 auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction);
Rui Ueyama136d27a2019-07-11 05:40:30 +0000459 if (!existingFunction->signature && sig)
460 existingFunction->signature = sig;
Sam Cleggfecfc592019-08-30 19:50:59 +0000461 if (isCalledDirectly && !signatureMatches(existingFunction, sig)) {
Sam Cleggfecfc592019-08-30 19:50:59 +0000462 // If the existing undefined functions is not called direcltly then let
463 // this one take precedence. Otherwise the existing function is either
464 // direclty called or defined, in which case we need a function variant.
465 if (existingUndefined && !existingUndefined->isCalledDirectly)
Rui Ueyama136d27a2019-07-11 05:40:30 +0000466 replaceSym();
Sam Cleggfecfc592019-08-30 19:50:59 +0000467 else if (getFunctionVariant(s, sig, file, &s))
468 replaceSym();
469 }
Sam Clegg67b05582019-10-17 05:16:54 +0000470 if (existingUndefined)
471 setImportAttributes(existingUndefined, importName, importModule, file);
Sam Clegg6540e572019-02-20 23:19:31 +0000472 }
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000473
Rui Ueyama136d27a2019-07-11 05:40:30 +0000474 return s;
Sam Cleggc94d3932017-11-17 18:14:09 +0000475}
476
Rui Ueyama136d27a2019-07-11 05:40:30 +0000477Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
478 InputFile *file) {
479 LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n");
Sam Cleggf6f4b982019-09-23 21:28:29 +0000480 assert(flags & WASM_SYMBOL_UNDEFINED);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000481
Rui Ueyama136d27a2019-07-11 05:40:30 +0000482 Symbol *s;
483 bool wasInserted;
484 std::tie(s, wasInserted) = insert(name, file);
485 if (s->traced)
486 printTraceSymbolUndefined(name, file);
Sam Cleggf989a922018-07-17 19:15:02 +0000487
Rui Ueyama136d27a2019-07-11 05:40:30 +0000488 if (wasInserted)
489 replaceSymbol<UndefinedData>(s, name, flags, file);
490 else if (auto *lazy = dyn_cast<LazySymbol>(s))
491 lazy->fetch();
492 else if (s->isDefined())
493 checkDataType(s, file);
494 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000495}
496
Rui Ueyama136d27a2019-07-11 05:40:30 +0000497Symbol *SymbolTable::addUndefinedGlobal(StringRef name, StringRef importName,
498 StringRef importModule, uint32_t flags,
499 InputFile *file,
500 const WasmGlobalType *type) {
501 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n");
Sam Cleggf6f4b982019-09-23 21:28:29 +0000502 assert(flags & WASM_SYMBOL_UNDEFINED);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000503
Rui Ueyama136d27a2019-07-11 05:40:30 +0000504 Symbol *s;
505 bool wasInserted;
506 std::tie(s, wasInserted) = insert(name, file);
507 if (s->traced)
508 printTraceSymbolUndefined(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000509
Rui Ueyama136d27a2019-07-11 05:40:30 +0000510 if (wasInserted)
511 replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags,
512 file, type);
513 else if (auto *lazy = dyn_cast<LazySymbol>(s))
514 lazy->fetch();
515 else if (s->isDefined())
516 checkGlobalType(s, file, type);
517 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000518}
519
Rui Ueyama136d27a2019-07-11 05:40:30 +0000520void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) {
521 LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n");
522 StringRef name = sym->getName();
Rui Ueyamac03c9042018-02-20 21:08:47 +0000523
Rui Ueyama136d27a2019-07-11 05:40:30 +0000524 Symbol *s;
525 bool wasInserted;
526 std::tie(s, wasInserted) = insertName(name);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000527
Rui Ueyama136d27a2019-07-11 05:40:30 +0000528 if (wasInserted) {
529 replaceSymbol<LazySymbol>(s, name, 0, file, *sym);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000530 return;
531 }
532
Rui Ueyama136d27a2019-07-11 05:40:30 +0000533 if (!s->isUndefined())
Sam Clegg37b4ee52019-01-29 22:26:31 +0000534 return;
535
536 // The existing symbol is undefined, load a new one from the archive,
Kazuaki Ishizaki7ae3d332020-01-06 10:21:05 -0800537 // unless the existing symbol is weak in which case replace the undefined
Sam Clegg37b4ee52019-01-29 22:26:31 +0000538 // symbols with a LazySymbol.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000539 if (s->isWeak()) {
540 const WasmSignature *oldSig = nullptr;
Sam Clegg37b4ee52019-01-29 22:26:31 +0000541 // In the case of an UndefinedFunction we need to preserve the expected
542 // signature.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000543 if (auto *f = dyn_cast<UndefinedFunction>(s))
544 oldSig = f->signature;
Sam Clegg37b4ee52019-01-29 22:26:31 +0000545 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000546 auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK,
547 file, *sym);
548 newSym->signature = oldSig;
Sam Clegg37b4ee52019-01-29 22:26:31 +0000549 return;
Sam Cleggc94d3932017-11-17 18:14:09 +0000550 }
Sam Clegg37b4ee52019-01-29 22:26:31 +0000551
552 LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000553 file->addMember(sym);
Sam Cleggc94d3932017-11-17 18:14:09 +0000554}
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000555
Rui Ueyama136d27a2019-07-11 05:40:30 +0000556bool SymbolTable::addComdat(StringRef name) {
557 return comdatGroups.insert(CachedHashStringRef(name)).second;
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000558}
Sam Clegg1f3f7742019-02-06 02:35:18 +0000559
Sam Clegg6540e572019-02-20 23:19:31 +0000560// The new signature doesn't match. Create a variant to the symbol with the
561// signature encoded in the name and return that instead. These symbols are
562// then unified later in handleSymbolVariants.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000563bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig,
564 const InputFile *file, Symbol **out) {
565 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> "
566 << " " << toString(*sig) << "\n");
567 Symbol *variant = nullptr;
Sam Clegg6540e572019-02-20 23:19:31 +0000568
569 // Linear search through symbol variants. Should never be more than two
570 // or three entries here.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000571 auto &variants = symVariants[CachedHashStringRef(sym->getName())];
572 if (variants.empty())
573 variants.push_back(sym);
Sam Clegg6540e572019-02-20 23:19:31 +0000574
Rui Ueyama136d27a2019-07-11 05:40:30 +0000575 for (Symbol* v : variants) {
576 if (*v->getSignature() == *sig) {
577 variant = v;
Sam Clegg6540e572019-02-20 23:19:31 +0000578 break;
579 }
580 }
581
Rui Ueyama136d27a2019-07-11 05:40:30 +0000582 bool wasAdded = !variant;
583 if (wasAdded) {
Sam Clegg6540e572019-02-20 23:19:31 +0000584 // Create a new variant;
585 LLVM_DEBUG(dbgs() << "added new variant\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000586 variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
587 variants.push_back(variant);
Sam Clegg6540e572019-02-20 23:19:31 +0000588 } else {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000589 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n");
590 assert(*variant->getSignature() == *sig);
Sam Clegg6540e572019-02-20 23:19:31 +0000591 }
592
Rui Ueyama136d27a2019-07-11 05:40:30 +0000593 *out = variant;
594 return wasAdded;
Sam Clegg6540e572019-02-20 23:19:31 +0000595}
596
Sam Clegg1f3f7742019-02-06 02:35:18 +0000597// Set a flag for --trace-symbol so that we can print out a log message
598// if a new symbol with the same name is inserted into the symbol table.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000599void SymbolTable::trace(StringRef name) {
600 symMap.insert({CachedHashStringRef(name), -1});
Sam Clegg1f3f7742019-02-06 02:35:18 +0000601}
Sam Clegg230dc112019-02-07 22:42:16 +0000602
Rui Ueyama136d27a2019-07-11 05:40:30 +0000603void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
Sam Clegga5ca34e2019-05-24 14:14:25 +0000604 // Swap symbols as instructed by -wrap.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000605 int &origIdx = symMap[CachedHashStringRef(sym->getName())];
606 int &realIdx= symMap[CachedHashStringRef(real->getName())];
607 int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())];
608 LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n");
Sam Clegga5ca34e2019-05-24 14:14:25 +0000609
610 // Anyone looking up __real symbols should get the original
Rui Ueyama136d27a2019-07-11 05:40:30 +0000611 realIdx = origIdx;
Sam Clegga5ca34e2019-05-24 14:14:25 +0000612 // Anyone looking up the original should get the __wrap symbol
Rui Ueyama136d27a2019-07-11 05:40:30 +0000613 origIdx = wrapIdx;
Sam Clegga5ca34e2019-05-24 14:14:25 +0000614}
615
Rui Ueyama136d27a2019-07-11 05:40:30 +0000616static const uint8_t unreachableFn[] = {
Sam Clegg230dc112019-02-07 22:42:16 +0000617 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
618 0x00 /* opcode unreachable */, 0x0b /* opcode end */
619};
620
621// Replace the given symbol body with an unreachable function.
622// This is used by handleWeakUndefines in order to generate a callable
Sam Clegg6540e572019-02-20 23:19:31 +0000623// equivalent of an undefined function and also handleSymbolVariants for
624// undefined functions that don't match the signature of the definition.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000625InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym,
626 const WasmSignature &sig,
627 StringRef debugName) {
628 auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName);
629 func->setBody(unreachableFn);
630 syntheticFunctions.emplace_back(func);
631 replaceSymbol<DefinedFunction>(sym, sym->getName(), sym->getFlags(), nullptr,
632 func);
633 return func;
Sam Clegg230dc112019-02-07 22:42:16 +0000634}
635
636// For weak undefined functions, there may be "call" instructions that reference
637// the symbol. In this case, we need to synthesise a dummy/stub function that
638// will abort at runtime, so that relocations can still provided an operand to
639// the call instruction that passes Wasm validation.
640void SymbolTable::handleWeakUndefines() {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000641 for (Symbol *sym : getSymbols()) {
642 if (!sym->isUndefWeak())
Sam Clegg230dc112019-02-07 22:42:16 +0000643 continue;
644
Rui Ueyama136d27a2019-07-11 05:40:30 +0000645 const WasmSignature *sig = sym->getSignature();
646 if (!sig) {
Sam Clegg230dc112019-02-07 22:42:16 +0000647 // It is possible for undefined functions not to have a signature (eg. if
648 // added via "--undefined"), but weak undefined ones do have a signature.
Sam Clegg6540e572019-02-20 23:19:31 +0000649 // Lazy symbols may not be functions and therefore Sig can still be null
Kazuaki Ishizaki7ae3d332020-01-06 10:21:05 -0800650 // in some circumstance.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000651 assert(!isa<FunctionSymbol>(sym));
Sam Clegg230dc112019-02-07 22:42:16 +0000652 continue;
Sam Clegg6540e572019-02-20 23:19:31 +0000653 }
Sam Clegg230dc112019-02-07 22:42:16 +0000654
655 // Add a synthetic dummy for weak undefined functions. These dummies will
656 // be GC'd if not used as the target of any "call" instructions.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000657 StringRef debugName = saver.save("undefined:" + toString(*sym));
658 InputFunction* func = replaceWithUnreachable(sym, *sig, debugName);
Sam Clegg230dc112019-02-07 22:42:16 +0000659 // Ensure it compares equal to the null pointer, and so that table relocs
660 // don't pull in the stub body (only call-operand relocs should do that).
Rui Ueyama136d27a2019-07-11 05:40:30 +0000661 func->setTableIndex(0);
Sam Clegg230dc112019-02-07 22:42:16 +0000662 // Hide our dummy to prevent export.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000663 sym->setHidden(true);
Sam Clegg230dc112019-02-07 22:42:16 +0000664 }
665}
Sam Clegg6540e572019-02-20 23:19:31 +0000666
Rui Ueyama136d27a2019-07-11 05:40:30 +0000667static void reportFunctionSignatureMismatch(StringRef symName,
668 FunctionSymbol *a,
669 FunctionSymbol *b, bool isError) {
670 std::string msg = ("function signature mismatch: " + symName +
671 "\n>>> defined as " + toString(*a->signature) + " in " +
672 toString(a->getFile()) + "\n>>> defined as " +
673 toString(*b->signature) + " in " + toString(b->getFile()))
Sam Clegg6540e572019-02-20 23:19:31 +0000674 .str();
Rui Ueyama136d27a2019-07-11 05:40:30 +0000675 if (isError)
Sam Clegg6540e572019-02-20 23:19:31 +0000676 error(msg);
677 else
678 warn(msg);
679}
680
681// Remove any variant symbols that were created due to function signature
682// mismatches.
683void SymbolTable::handleSymbolVariants() {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000684 for (auto pair : symVariants) {
Sam Clegg6540e572019-02-20 23:19:31 +0000685 // Push the initial symbol onto the list of variants.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000686 StringRef symName = pair.first.val();
687 std::vector<Symbol *> &variants = pair.second;
Sam Clegg6540e572019-02-20 23:19:31 +0000688
689#ifndef NDEBUG
Rui Ueyama136d27a2019-07-11 05:40:30 +0000690 LLVM_DEBUG(dbgs() << "symbol with (" << variants.size()
691 << ") variants: " << symName << "\n");
692 for (auto *s: variants) {
693 auto *f = cast<FunctionSymbol>(s);
694 LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " "
695 << toString(*f->signature) << "\n");
Sam Clegg6540e572019-02-20 23:19:31 +0000696 }
697#endif
698
699 // Find the one definition.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000700 DefinedFunction *defined = nullptr;
701 for (auto *symbol : variants) {
702 if (auto f = dyn_cast<DefinedFunction>(symbol)) {
703 defined = f;
Sam Clegg6540e572019-02-20 23:19:31 +0000704 break;
705 }
706 }
707
708 // If there are no definitions, and the undefined symbols disagree on
709 // the signature, there is not we can do since we don't know which one
710 // to use as the signature on the import.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000711 if (!defined) {
712 reportFunctionSignatureMismatch(symName,
713 cast<FunctionSymbol>(variants[0]),
714 cast<FunctionSymbol>(variants[1]), true);
Sam Clegg6540e572019-02-20 23:19:31 +0000715 return;
716 }
717
Rui Ueyama136d27a2019-07-11 05:40:30 +0000718 for (auto *symbol : variants) {
719 if (symbol != defined) {
720 auto *f = cast<FunctionSymbol>(symbol);
721 reportFunctionSignatureMismatch(symName, f, defined, false);
Sam Clegg51b521c2020-01-16 14:36:44 -0800722 StringRef debugName = saver.save("signature_mismatch:" + toString(*f));
Rui Ueyama136d27a2019-07-11 05:40:30 +0000723 replaceWithUnreachable(f, *f->signature, debugName);
Sam Clegg6540e572019-02-20 23:19:31 +0000724 }
725 }
726 }
727}
Fangrui Song33c59ab2019-10-10 05:25:39 +0000728
729} // namespace wasm
730} // namespace lld