1//===- Symbols.cpp --------------------------------------------------------===//
2//
3// 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
6//
7//===----------------------------------------------------------------------===//
8
9#include "Symbols.h"
10#include "Config.h"
11#include "InputChunks.h"
12#include "InputElement.h"
13#include "InputFiles.h"
14#include "OutputSections.h"
15#include "OutputSegment.h"
16#include "SymbolTable.h"
17#include "lld/Common/ErrorHandler.h"
18#include "lld/Common/Memory.h"
19#include "llvm/Demangle/Demangle.h"
20
21#define DEBUG_TYPE "lld"
22
23using namespace llvm;
24using namespace llvm::object;
25using namespace llvm::wasm;
26using namespace lld::wasm;
27
28namespace lld {
29std::string toString(const wasm::Symbol &sym) {
30 return maybeDemangleSymbol(name: sym.getName());
31}
32
33std::string maybeDemangleSymbol(StringRef name) {
34 // WebAssembly requires caller and callee signatures to match, so we mangle
35 // `main` in the case where we need to pass it arguments.
36 if (name == "__main_argc_argv")
37 return "main";
38 if (wasm::config->demangle)
39 return demangle(MangledName: name);
40 return name.str();
41}
42
43std::string toString(wasm::Symbol::Kind kind) {
44 switch (kind) {
45 case wasm::Symbol::DefinedFunctionKind:
46 return "DefinedFunction";
47 case wasm::Symbol::DefinedDataKind:
48 return "DefinedData";
49 case wasm::Symbol::DefinedGlobalKind:
50 return "DefinedGlobal";
51 case wasm::Symbol::DefinedTableKind:
52 return "DefinedTable";
53 case wasm::Symbol::DefinedTagKind:
54 return "DefinedTag";
55 case wasm::Symbol::UndefinedFunctionKind:
56 return "UndefinedFunction";
57 case wasm::Symbol::UndefinedDataKind:
58 return "UndefinedData";
59 case wasm::Symbol::UndefinedGlobalKind:
60 return "UndefinedGlobal";
61 case wasm::Symbol::UndefinedTableKind:
62 return "UndefinedTable";
63 case wasm::Symbol::UndefinedTagKind:
64 return "UndefinedTag";
65 case wasm::Symbol::LazyKind:
66 return "LazyKind";
67 case wasm::Symbol::SectionKind:
68 return "SectionKind";
69 case wasm::Symbol::OutputSectionKind:
70 return "OutputSectionKind";
71 case wasm::Symbol::SharedFunctionKind:
72 return "SharedFunctionKind";
73 case wasm::Symbol::SharedDataKind:
74 return "SharedDataKind";
75 }
76 llvm_unreachable("invalid symbol kind");
77}
78
79namespace wasm {
80DefinedFunction *WasmSym::callCtors;
81DefinedFunction *WasmSym::callDtors;
82DefinedFunction *WasmSym::initMemory;
83DefinedFunction *WasmSym::applyDataRelocs;
84DefinedFunction *WasmSym::applyGlobalRelocs;
85DefinedFunction *WasmSym::applyTLSRelocs;
86DefinedFunction *WasmSym::applyGlobalTLSRelocs;
87DefinedFunction *WasmSym::initTLS;
88DefinedFunction *WasmSym::startFunction;
89DefinedData *WasmSym::dsoHandle;
90DefinedData *WasmSym::dataEnd;
91DefinedData *WasmSym::globalBase;
92DefinedData *WasmSym::heapBase;
93DefinedData *WasmSym::heapEnd;
94DefinedData *WasmSym::initMemoryFlag;
95GlobalSymbol *WasmSym::stackPointer;
96DefinedData *WasmSym::stackLow;
97DefinedData *WasmSym::stackHigh;
98GlobalSymbol *WasmSym::tlsBase;
99GlobalSymbol *WasmSym::tlsSize;
100GlobalSymbol *WasmSym::tlsAlign;
101UndefinedGlobal *WasmSym::tableBase;
102DefinedData *WasmSym::definedTableBase;
103UndefinedGlobal *WasmSym::memoryBase;
104DefinedData *WasmSym::definedMemoryBase;
105TableSymbol *WasmSym::indirectFunctionTable;
106
107WasmSymbolType Symbol::getWasmType() const {
108 if (isa<FunctionSymbol>(Val: this))
109 return WASM_SYMBOL_TYPE_FUNCTION;
110 if (isa<DataSymbol>(Val: this))
111 return WASM_SYMBOL_TYPE_DATA;
112 if (isa<GlobalSymbol>(Val: this))
113 return WASM_SYMBOL_TYPE_GLOBAL;
114 if (isa<TagSymbol>(Val: this))
115 return WASM_SYMBOL_TYPE_TAG;
116 if (isa<TableSymbol>(Val: this))
117 return WASM_SYMBOL_TYPE_TABLE;
118 if (isa<SectionSymbol>(Val: this) || isa<OutputSectionSymbol>(Val: this))
119 return WASM_SYMBOL_TYPE_SECTION;
120 llvm_unreachable("invalid symbol kind");
121}
122
123const WasmSignature *Symbol::getSignature() const {
124 if (auto* f = dyn_cast<FunctionSymbol>(Val: this))
125 return f->signature;
126 if (auto *t = dyn_cast<TagSymbol>(Val: this))
127 return t->signature;
128 if (auto *l = dyn_cast<LazySymbol>(Val: this))
129 return l->signature;
130 return nullptr;
131}
132
133InputChunk *Symbol::getChunk() const {
134 if (auto *f = dyn_cast<DefinedFunction>(Val: this))
135 return f->function;
136 if (auto *f = dyn_cast<UndefinedFunction>(Val: this))
137 if (f->stubFunction)
138 return f->stubFunction->function;
139 if (auto *d = dyn_cast<DefinedData>(Val: this))
140 return d->segment;
141 return nullptr;
142}
143
144bool Symbol::isDiscarded() const {
145 if (InputChunk *c = getChunk())
146 return c->discarded;
147 return false;
148}
149
150bool Symbol::isLive() const {
151 if (auto *g = dyn_cast<DefinedGlobal>(Val: this))
152 return g->global->live;
153 if (auto *t = dyn_cast<DefinedTag>(Val: this))
154 return t->tag->live;
155 if (auto *t = dyn_cast<DefinedTable>(Val: this))
156 return t->table->live;
157 if (InputChunk *c = getChunk())
158 return c->live;
159 return referenced;
160}
161
162void Symbol::markLive() {
163 assert(!isDiscarded());
164 referenced = true;
165 if (file != nullptr && isDefined())
166 file->markLive();
167 if (auto *g = dyn_cast<DefinedGlobal>(Val: this))
168 g->global->live = true;
169 if (auto *t = dyn_cast<DefinedTag>(Val: this))
170 t->tag->live = true;
171 if (auto *t = dyn_cast<DefinedTable>(Val: this))
172 t->table->live = true;
173 if (InputChunk *c = getChunk()) {
174 // Usually, a whole chunk is marked as live or dead, but in mergeable
175 // (splittable) sections, each piece of data has independent liveness bit.
176 // So we explicitly tell it which offset is in use.
177 if (auto *d = dyn_cast<DefinedData>(Val: this)) {
178 if (auto *ms = dyn_cast<MergeInputChunk>(Val: c)) {
179 ms->getSectionPiece(offset: d->value)->live = true;
180 }
181 }
182 c->live = true;
183 }
184}
185
186uint32_t Symbol::getOutputSymbolIndex() const {
187 assert(outputSymbolIndex != INVALID_INDEX);
188 return outputSymbolIndex;
189}
190
191void Symbol::setOutputSymbolIndex(uint32_t index) {
192 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index
193 << "\n");
194 assert(outputSymbolIndex == INVALID_INDEX);
195 outputSymbolIndex = index;
196}
197
198void Symbol::setGOTIndex(uint32_t index) {
199 LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");
200 assert(gotIndex == INVALID_INDEX);
201 gotIndex = index;
202}
203
204bool Symbol::isWeak() const {
205 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
206}
207
208bool Symbol::isLocal() const {
209 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
210}
211
212bool Symbol::isHidden() const {
213 return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
214}
215
216bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; }
217
218void Symbol::setHidden(bool isHidden) {
219 LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
220 flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
221 if (isHidden)
222 flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
223 else
224 flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
225}
226
227bool Symbol::isImported() const {
228 return isShared() ||
229 (isUndefined() && (importName.has_value() || forceImport));
230}
231
232bool Symbol::isExported() const {
233 if (!isDefined() || isShared() || isLocal())
234 return false;
235
236 // Shared libraries must export all weakly defined symbols
237 // in case they contain the version that will be chosen by
238 // the dynamic linker.
239 if (config->shared && isLive() && isWeak() && !isHidden())
240 return true;
241
242 if (config->exportAll || (config->exportDynamic && !isHidden()))
243 return true;
244
245 return isExportedExplicit();
246}
247
248bool Symbol::isExportedExplicit() const {
249 return forceExport || flags & WASM_SYMBOL_EXPORTED;
250}
251
252bool Symbol::isNoStrip() const {
253 return flags & WASM_SYMBOL_NO_STRIP;
254}
255
256uint32_t FunctionSymbol::getFunctionIndex() const {
257 if (const auto *u = dyn_cast<UndefinedFunction>(Val: this))
258 if (u->stubFunction)
259 return u->stubFunction->getFunctionIndex();
260 if (functionIndex != INVALID_INDEX)
261 return functionIndex;
262 auto *f = cast<DefinedFunction>(Val: this);
263 return f->function->getFunctionIndex();
264}
265
266void FunctionSymbol::setFunctionIndex(uint32_t index) {
267 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");
268 assert(functionIndex == INVALID_INDEX);
269 functionIndex = index;
270}
271
272bool FunctionSymbol::hasFunctionIndex() const {
273 if (auto *f = dyn_cast<DefinedFunction>(Val: this))
274 return f->function->hasFunctionIndex();
275 return functionIndex != INVALID_INDEX;
276}
277
278uint32_t FunctionSymbol::getTableIndex() const {
279 if (auto *f = dyn_cast<DefinedFunction>(Val: this))
280 return f->function->getTableIndex();
281 assert(tableIndex != INVALID_INDEX);
282 return tableIndex;
283}
284
285bool FunctionSymbol::hasTableIndex() const {
286 if (auto *f = dyn_cast<DefinedFunction>(Val: this))
287 return f->function->hasTableIndex();
288 return tableIndex != INVALID_INDEX;
289}
290
291void FunctionSymbol::setTableIndex(uint32_t index) {
292 // For imports, we set the table index here on the Symbol; for defined
293 // functions we set the index on the InputFunction so that we don't export
294 // the same thing twice (keeps the table size down).
295 if (auto *f = dyn_cast<DefinedFunction>(Val: this)) {
296 f->function->setTableIndex(index);
297 return;
298 }
299 LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");
300 assert(tableIndex == INVALID_INDEX);
301 tableIndex = index;
302}
303
304DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
305 InputFunction *function)
306 : FunctionSymbol(name, DefinedFunctionKind, flags, f,
307 function ? &function->signature : nullptr),
308 function(function) {}
309
310uint32_t DefinedFunction::getExportedFunctionIndex() const {
311 return function->getFunctionIndex();
312}
313
314uint64_t DefinedData::getVA() const {
315 LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
316 // In the shared memory case, TLS symbols are relative to the start of the TLS
317 // output segment (__tls_base). When building without shared memory, TLS
318 // symbols absolute, just like non-TLS.
319 if (isTLS() && config->sharedMemory)
320 return getOutputSegmentOffset();
321 if (segment)
322 return segment->getVA(offset: value);
323 return value;
324}
325
326void DefinedData::setVA(uint64_t value_) {
327 LLVM_DEBUG(dbgs() << "setVA " << name << " -> " << value_ << "\n");
328 assert(!segment);
329 value = value_;
330}
331
332uint64_t DefinedData::getOutputSegmentOffset() const {
333 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
334 return segment->getChunkOffset(offset: value);
335}
336
337uint64_t DefinedData::getOutputSegmentIndex() const {
338 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
339 return segment->outputSeg->index;
340}
341
342uint32_t GlobalSymbol::getGlobalIndex() const {
343 if (auto *f = dyn_cast<DefinedGlobal>(Val: this))
344 return f->global->getAssignedIndex();
345 assert(globalIndex != INVALID_INDEX);
346 return globalIndex;
347}
348
349void GlobalSymbol::setGlobalIndex(uint32_t index) {
350 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");
351 assert(globalIndex == INVALID_INDEX);
352 globalIndex = index;
353}
354
355bool GlobalSymbol::hasGlobalIndex() const {
356 if (auto *f = dyn_cast<DefinedGlobal>(Val: this))
357 return f->global->hasAssignedIndex();
358 return globalIndex != INVALID_INDEX;
359}
360
361DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
362 InputGlobal *global)
363 : GlobalSymbol(name, DefinedGlobalKind, flags, file,
364 global ? &global->getType() : nullptr),
365 global(global) {}
366
367uint32_t TagSymbol::getTagIndex() const {
368 if (auto *f = dyn_cast<DefinedTag>(Val: this))
369 return f->tag->getAssignedIndex();
370 assert(tagIndex != INVALID_INDEX);
371 return tagIndex;
372}
373
374void TagSymbol::setTagIndex(uint32_t index) {
375 LLVM_DEBUG(dbgs() << "setTagIndex " << name << " -> " << index << "\n");
376 assert(tagIndex == INVALID_INDEX);
377 tagIndex = index;
378}
379
380bool TagSymbol::hasTagIndex() const {
381 if (auto *f = dyn_cast<DefinedTag>(Val: this))
382 return f->tag->hasAssignedIndex();
383 return tagIndex != INVALID_INDEX;
384}
385
386DefinedTag::DefinedTag(StringRef name, uint32_t flags, InputFile *file,
387 InputTag *tag)
388 : TagSymbol(name, DefinedTagKind, flags, file,
389 tag ? &tag->signature : nullptr),
390 tag(tag) {}
391
392void TableSymbol::setLimits(const WasmLimits &limits) {
393 if (auto *t = dyn_cast<DefinedTable>(Val: this))
394 t->table->setLimits(limits);
395 auto *newType = make<WasmTableType>(args: *tableType);
396 newType->Limits = limits;
397 tableType = newType;
398}
399
400uint32_t TableSymbol::getTableNumber() const {
401 if (const auto *t = dyn_cast<DefinedTable>(Val: this))
402 return t->table->getAssignedIndex();
403 assert(tableNumber != INVALID_INDEX);
404 return tableNumber;
405}
406
407void TableSymbol::setTableNumber(uint32_t number) {
408 if (const auto *t = dyn_cast<DefinedTable>(Val: this))
409 return t->table->assignIndex(index: number);
410 LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n");
411 assert(tableNumber == INVALID_INDEX);
412 tableNumber = number;
413}
414
415bool TableSymbol::hasTableNumber() const {
416 if (const auto *t = dyn_cast<DefinedTable>(Val: this))
417 return t->table->hasAssignedIndex();
418 return tableNumber != INVALID_INDEX;
419}
420
421DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file,
422 InputTable *table)
423 : TableSymbol(name, DefinedTableKind, flags, file,
424 table ? &table->getType() : nullptr),
425 table(table) {}
426
427const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
428 assert(section->outputSec && section->outputSec->sectionSym);
429 return section->outputSec->sectionSym;
430}
431
432void LazySymbol::extract() {
433 if (file->lazy) {
434 file->lazy = false;
435 symtab->addFile(file, symName: name);
436 }
437}
438
439void LazySymbol::setWeak() {
440 flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK;
441}
442
443void printTraceSymbolUndefined(StringRef name, const InputFile* file) {
444 message(msg: toString(file) + ": reference to " + name);
445}
446
447// Print out a log message for --trace-symbol.
448void printTraceSymbol(Symbol *sym) {
449 // Undefined symbols are traced via printTraceSymbolUndefined
450 if (sym->isUndefined())
451 return;
452
453 std::string s;
454 if (sym->isLazy())
455 s = ": lazy definition of ";
456 else
457 s = ": definition of ";
458
459 message(msg: toString(file: sym->getFile()) + s + sym->getName());
460}
461
462const char *defaultModule = "env";
463const char *functionTableName = "__indirect_function_table";
464const char *memoryName = "memory";
465
466} // namespace wasm
467} // namespace lld
468