1ece8a530Spatrick //===- Symbols.h ------------------------------------------------*- C++ -*-===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick
9ece8a530Spatrick #ifndef LLD_WASM_SYMBOLS_H
10ece8a530Spatrick #define LLD_WASM_SYMBOLS_H
11ece8a530Spatrick
12ece8a530Spatrick #include "Config.h"
13ece8a530Spatrick #include "lld/Common/LLVM.h"
14ece8a530Spatrick #include "llvm/Object/Archive.h"
15ece8a530Spatrick #include "llvm/Object/Wasm.h"
16*dfe94b16Srobert #include <optional>
17ece8a530Spatrick
18ece8a530Spatrick namespace lld {
19ece8a530Spatrick namespace wasm {
20ece8a530Spatrick
21ece8a530Spatrick // Shared string constants
22ece8a530Spatrick
23ece8a530Spatrick // The default module name to use for symbol imports.
24ece8a530Spatrick extern const char *defaultModule;
25ece8a530Spatrick
26ece8a530Spatrick // The name under which to import or export the wasm table.
27ece8a530Spatrick extern const char *functionTableName;
28ece8a530Spatrick
29*dfe94b16Srobert // The name under which to import or export the wasm memory.
30*dfe94b16Srobert extern const char *memoryName;
31*dfe94b16Srobert
32ece8a530Spatrick using llvm::wasm::WasmSymbolType;
33ece8a530Spatrick
34ece8a530Spatrick class InputFile;
35ece8a530Spatrick class InputChunk;
36ece8a530Spatrick class InputSegment;
37ece8a530Spatrick class InputFunction;
38ece8a530Spatrick class InputGlobal;
391cf9926bSpatrick class InputTag;
40ece8a530Spatrick class InputSection;
411cf9926bSpatrick class InputTable;
42ece8a530Spatrick class OutputSection;
43ece8a530Spatrick
44ece8a530Spatrick #define INVALID_INDEX UINT32_MAX
45ece8a530Spatrick
46ece8a530Spatrick // The base class for real symbol classes.
47ece8a530Spatrick class Symbol {
48ece8a530Spatrick public:
49ece8a530Spatrick enum Kind : uint8_t {
50ece8a530Spatrick DefinedFunctionKind,
51ece8a530Spatrick DefinedDataKind,
52ece8a530Spatrick DefinedGlobalKind,
531cf9926bSpatrick DefinedTagKind,
541cf9926bSpatrick DefinedTableKind,
55ece8a530Spatrick SectionKind,
56ece8a530Spatrick OutputSectionKind,
57ece8a530Spatrick UndefinedFunctionKind,
58ece8a530Spatrick UndefinedDataKind,
59ece8a530Spatrick UndefinedGlobalKind,
601cf9926bSpatrick UndefinedTableKind,
61*dfe94b16Srobert UndefinedTagKind,
62ece8a530Spatrick LazyKind,
63ece8a530Spatrick };
64ece8a530Spatrick
kind()65ece8a530Spatrick Kind kind() const { return symbolKind; }
66ece8a530Spatrick
isDefined()67ece8a530Spatrick bool isDefined() const { return !isLazy() && !isUndefined(); }
68ece8a530Spatrick
isUndefined()69ece8a530Spatrick bool isUndefined() const {
70ece8a530Spatrick return symbolKind == UndefinedFunctionKind ||
711cf9926bSpatrick symbolKind == UndefinedDataKind ||
721cf9926bSpatrick symbolKind == UndefinedGlobalKind ||
73*dfe94b16Srobert symbolKind == UndefinedTableKind || symbolKind == UndefinedTagKind;
74ece8a530Spatrick }
75ece8a530Spatrick
isLazy()76ece8a530Spatrick bool isLazy() const { return symbolKind == LazyKind; }
77ece8a530Spatrick
78ece8a530Spatrick bool isLocal() const;
79ece8a530Spatrick bool isWeak() const;
80ece8a530Spatrick bool isHidden() const;
81*dfe94b16Srobert bool isTLS() const;
82ece8a530Spatrick
83ece8a530Spatrick // Returns true if this symbol exists in a discarded (due to COMDAT) section
84ece8a530Spatrick bool isDiscarded() const;
85ece8a530Spatrick
86ece8a530Spatrick // True if this is an undefined weak symbol. This only works once
87ece8a530Spatrick // all input files have been added.
isUndefWeak()88ece8a530Spatrick bool isUndefWeak() const {
89ece8a530Spatrick // See comment on lazy symbols for details.
90ece8a530Spatrick return isWeak() && (isUndefined() || isLazy());
91ece8a530Spatrick }
92ece8a530Spatrick
93ece8a530Spatrick // Returns the symbol name.
getName()94ece8a530Spatrick StringRef getName() const { return name; }
95ece8a530Spatrick
96ece8a530Spatrick // Returns the file from which this symbol was created.
getFile()97ece8a530Spatrick InputFile *getFile() const { return file; }
98ece8a530Spatrick
99ece8a530Spatrick InputChunk *getChunk() const;
100ece8a530Spatrick
101ece8a530Spatrick // Indicates that the section or import for this symbol will be included in
102ece8a530Spatrick // the final image.
103ece8a530Spatrick bool isLive() const;
104ece8a530Spatrick
105ece8a530Spatrick // Marks the symbol's InputChunk as Live, so that it will be included in the
106ece8a530Spatrick // final image.
107ece8a530Spatrick void markLive();
108ece8a530Spatrick
109ece8a530Spatrick void setHidden(bool isHidden);
110ece8a530Spatrick
111ece8a530Spatrick // Get/set the index in the output symbol table. This is only used for
112ece8a530Spatrick // relocatable output.
113ece8a530Spatrick uint32_t getOutputSymbolIndex() const;
114ece8a530Spatrick void setOutputSymbolIndex(uint32_t index);
115ece8a530Spatrick
116ece8a530Spatrick WasmSymbolType getWasmType() const;
117*dfe94b16Srobert bool isImported() const;
118ece8a530Spatrick bool isExported() const;
1191cf9926bSpatrick bool isExportedExplicit() const;
120ece8a530Spatrick
121ece8a530Spatrick // Indicates that the symbol is used in an __attribute__((used)) directive
122ece8a530Spatrick // or similar.
123ece8a530Spatrick bool isNoStrip() const;
124ece8a530Spatrick
125ece8a530Spatrick const WasmSignature* getSignature() const;
126ece8a530Spatrick
getGOTIndex()127ece8a530Spatrick uint32_t getGOTIndex() const {
128ece8a530Spatrick assert(gotIndex != INVALID_INDEX);
129ece8a530Spatrick return gotIndex;
130ece8a530Spatrick }
131ece8a530Spatrick
132ece8a530Spatrick void setGOTIndex(uint32_t index);
hasGOTIndex()133ece8a530Spatrick bool hasGOTIndex() const { return gotIndex != INVALID_INDEX; }
134ece8a530Spatrick
135ece8a530Spatrick protected:
Symbol(StringRef name,Kind k,uint32_t flags,InputFile * f)136ece8a530Spatrick Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
137bb684c34Spatrick : name(name), file(f), symbolKind(k), referenced(!config->gcSections),
138bb684c34Spatrick requiresGOT(false), isUsedInRegularObj(false), forceExport(false),
139*dfe94b16Srobert forceImport(false), canInline(false), traced(false), isStub(false),
140*dfe94b16Srobert flags(flags) {}
141ece8a530Spatrick
142ece8a530Spatrick StringRef name;
143ece8a530Spatrick InputFile *file;
144ece8a530Spatrick uint32_t outputSymbolIndex = INVALID_INDEX;
145ece8a530Spatrick uint32_t gotIndex = INVALID_INDEX;
146ece8a530Spatrick Kind symbolKind;
147ece8a530Spatrick
148ece8a530Spatrick public:
149ece8a530Spatrick bool referenced : 1;
150ece8a530Spatrick
151ece8a530Spatrick // True for data symbols that needs a dummy GOT entry. Used for static
152ece8a530Spatrick // linking of GOT accesses.
153ece8a530Spatrick bool requiresGOT : 1;
154ece8a530Spatrick
155ece8a530Spatrick // True if the symbol was used for linking and thus need to be added to the
156ece8a530Spatrick // output file's symbol table. This is true for all symbols except for
157ece8a530Spatrick // unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that
158ece8a530Spatrick // are unreferenced except by other bitcode objects.
159ece8a530Spatrick bool isUsedInRegularObj : 1;
160ece8a530Spatrick
161*dfe94b16Srobert // True if this symbol is explicitly marked for export (i.e. via the
162ece8a530Spatrick // -e/--export command line flag)
163ece8a530Spatrick bool forceExport : 1;
164ece8a530Spatrick
165*dfe94b16Srobert bool forceImport : 1;
166*dfe94b16Srobert
167ece8a530Spatrick // False if LTO shouldn't inline whatever this symbol points to. If a symbol
168ece8a530Spatrick // is overwritten after LTO, LTO shouldn't inline the symbol because it
169ece8a530Spatrick // doesn't know the final contents of the symbol.
170ece8a530Spatrick bool canInline : 1;
171ece8a530Spatrick
172ece8a530Spatrick // True if this symbol is specified by --trace-symbol option.
173ece8a530Spatrick bool traced : 1;
174bb684c34Spatrick
1751cf9926bSpatrick // True if this symbol is a linker-synthesized stub function (traps when
1761cf9926bSpatrick // called) and should otherwise be treated as missing/undefined. See
1771cf9926bSpatrick // SymbolTable::replaceWithUndefined.
1781cf9926bSpatrick // These stubs never appear in the table and any table index relocations
1791cf9926bSpatrick // against them will produce address 0 (The table index representing
1801cf9926bSpatrick // the null function pointer).
1811cf9926bSpatrick bool isStub : 1;
1821cf9926bSpatrick
183bb684c34Spatrick uint32_t flags;
1841cf9926bSpatrick
185*dfe94b16Srobert std::optional<StringRef> importName;
186*dfe94b16Srobert std::optional<StringRef> importModule;
187ece8a530Spatrick };
188ece8a530Spatrick
189ece8a530Spatrick class FunctionSymbol : public Symbol {
190ece8a530Spatrick public:
classof(const Symbol * s)191ece8a530Spatrick static bool classof(const Symbol *s) {
192ece8a530Spatrick return s->kind() == DefinedFunctionKind ||
193ece8a530Spatrick s->kind() == UndefinedFunctionKind;
194ece8a530Spatrick }
195ece8a530Spatrick
196ece8a530Spatrick // Get/set the table index
197ece8a530Spatrick void setTableIndex(uint32_t index);
198ece8a530Spatrick uint32_t getTableIndex() const;
199ece8a530Spatrick bool hasTableIndex() const;
200ece8a530Spatrick
201ece8a530Spatrick // Get/set the function index
202ece8a530Spatrick uint32_t getFunctionIndex() const;
203ece8a530Spatrick void setFunctionIndex(uint32_t index);
204ece8a530Spatrick bool hasFunctionIndex() const;
205ece8a530Spatrick
206ece8a530Spatrick const WasmSignature *signature;
207ece8a530Spatrick
208ece8a530Spatrick protected:
FunctionSymbol(StringRef name,Kind k,uint32_t flags,InputFile * f,const WasmSignature * sig)209ece8a530Spatrick FunctionSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
210ece8a530Spatrick const WasmSignature *sig)
211ece8a530Spatrick : Symbol(name, k, flags, f), signature(sig) {}
212ece8a530Spatrick
213ece8a530Spatrick uint32_t tableIndex = INVALID_INDEX;
214ece8a530Spatrick uint32_t functionIndex = INVALID_INDEX;
215ece8a530Spatrick };
216ece8a530Spatrick
217ece8a530Spatrick class DefinedFunction : public FunctionSymbol {
218ece8a530Spatrick public:
219ece8a530Spatrick DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
220ece8a530Spatrick InputFunction *function);
221ece8a530Spatrick
classof(const Symbol * s)222ece8a530Spatrick static bool classof(const Symbol *s) {
223ece8a530Spatrick return s->kind() == DefinedFunctionKind;
224ece8a530Spatrick }
225ece8a530Spatrick
226*dfe94b16Srobert // Get the function index to be used when exporting. This only applies to
227*dfe94b16Srobert // defined functions and can be differ from the regular function index for
228*dfe94b16Srobert // weakly defined functions (that are imported and used via one index but
229*dfe94b16Srobert // defined and exported via another).
230*dfe94b16Srobert uint32_t getExportedFunctionIndex() const;
231*dfe94b16Srobert
232ece8a530Spatrick InputFunction *function;
233ece8a530Spatrick };
234ece8a530Spatrick
235ece8a530Spatrick class UndefinedFunction : public FunctionSymbol {
236ece8a530Spatrick public:
237*dfe94b16Srobert UndefinedFunction(StringRef name, std::optional<StringRef> importName,
238*dfe94b16Srobert std::optional<StringRef> importModule, uint32_t flags,
239ece8a530Spatrick InputFile *file = nullptr,
240ece8a530Spatrick const WasmSignature *type = nullptr,
241ece8a530Spatrick bool isCalledDirectly = true)
FunctionSymbol(name,UndefinedFunctionKind,flags,file,type)242ece8a530Spatrick : FunctionSymbol(name, UndefinedFunctionKind, flags, file, type),
2431cf9926bSpatrick isCalledDirectly(isCalledDirectly) {
2441cf9926bSpatrick this->importName = importName;
2451cf9926bSpatrick this->importModule = importModule;
2461cf9926bSpatrick }
247ece8a530Spatrick
classof(const Symbol * s)248ece8a530Spatrick static bool classof(const Symbol *s) {
249ece8a530Spatrick return s->kind() == UndefinedFunctionKind;
250ece8a530Spatrick }
251ece8a530Spatrick
2521cf9926bSpatrick DefinedFunction *stubFunction = nullptr;
253ece8a530Spatrick bool isCalledDirectly;
254ece8a530Spatrick };
255ece8a530Spatrick
256ece8a530Spatrick // Section symbols for output sections are different from those for input
257ece8a530Spatrick // section. These are generated by the linker and point the OutputSection
258ece8a530Spatrick // rather than an InputSection.
259ece8a530Spatrick class OutputSectionSymbol : public Symbol {
260ece8a530Spatrick public:
OutputSectionSymbol(const OutputSection * s)261ece8a530Spatrick OutputSectionSymbol(const OutputSection *s)
262ece8a530Spatrick : Symbol("", OutputSectionKind, llvm::wasm::WASM_SYMBOL_BINDING_LOCAL,
263ece8a530Spatrick nullptr),
264ece8a530Spatrick section(s) {}
265ece8a530Spatrick
classof(const Symbol * s)266ece8a530Spatrick static bool classof(const Symbol *s) {
267ece8a530Spatrick return s->kind() == OutputSectionKind;
268ece8a530Spatrick }
269ece8a530Spatrick
270ece8a530Spatrick const OutputSection *section;
271ece8a530Spatrick };
272ece8a530Spatrick
273ece8a530Spatrick class SectionSymbol : public Symbol {
274ece8a530Spatrick public:
2751cf9926bSpatrick SectionSymbol(uint32_t flags, const InputChunk *s, InputFile *f = nullptr)
276ece8a530Spatrick : Symbol("", SectionKind, flags, f), section(s) {}
277ece8a530Spatrick
classof(const Symbol * s)278ece8a530Spatrick static bool classof(const Symbol *s) { return s->kind() == SectionKind; }
279ece8a530Spatrick
280ece8a530Spatrick const OutputSectionSymbol *getOutputSectionSymbol() const;
281ece8a530Spatrick
2821cf9926bSpatrick const InputChunk *section;
283ece8a530Spatrick };
284ece8a530Spatrick
285ece8a530Spatrick class DataSymbol : public Symbol {
286ece8a530Spatrick public:
classof(const Symbol * s)287ece8a530Spatrick static bool classof(const Symbol *s) {
288ece8a530Spatrick return s->kind() == DefinedDataKind || s->kind() == UndefinedDataKind;
289ece8a530Spatrick }
290ece8a530Spatrick
291ece8a530Spatrick protected:
DataSymbol(StringRef name,Kind k,uint32_t flags,InputFile * f)292ece8a530Spatrick DataSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
293ece8a530Spatrick : Symbol(name, k, flags, f) {}
294ece8a530Spatrick };
295ece8a530Spatrick
296ece8a530Spatrick class DefinedData : public DataSymbol {
297ece8a530Spatrick public:
298ece8a530Spatrick // Constructor for regular data symbols originating from input files.
DefinedData(StringRef name,uint32_t flags,InputFile * f,InputChunk * segment,uint64_t value,uint64_t size)2991cf9926bSpatrick DefinedData(StringRef name, uint32_t flags, InputFile *f, InputChunk *segment,
3001cf9926bSpatrick uint64_t value, uint64_t size)
301ece8a530Spatrick : DataSymbol(name, DefinedDataKind, flags, f), segment(segment),
3021cf9926bSpatrick value(value), size(size) {}
303ece8a530Spatrick
304ece8a530Spatrick // Constructor for linker synthetic data symbols.
DefinedData(StringRef name,uint32_t flags)305ece8a530Spatrick DefinedData(StringRef name, uint32_t flags)
306ece8a530Spatrick : DataSymbol(name, DefinedDataKind, flags, nullptr) {}
307ece8a530Spatrick
classof(const Symbol * s)308ece8a530Spatrick static bool classof(const Symbol *s) { return s->kind() == DefinedDataKind; }
309ece8a530Spatrick
310ece8a530Spatrick // Returns the output virtual address of a defined data symbol.
3111cf9926bSpatrick uint64_t getVA() const;
3121cf9926bSpatrick void setVA(uint64_t va);
313ece8a530Spatrick
314ece8a530Spatrick // Returns the offset of a defined data symbol within its OutputSegment.
315bb684c34Spatrick uint64_t getOutputSegmentOffset() const;
316bb684c34Spatrick uint64_t getOutputSegmentIndex() const;
getSize()317bb684c34Spatrick uint64_t getSize() const { return size; }
318ece8a530Spatrick
3191cf9926bSpatrick InputChunk *segment = nullptr;
3201cf9926bSpatrick uint64_t value = 0;
321ece8a530Spatrick
322ece8a530Spatrick protected:
323bb684c34Spatrick uint64_t size = 0;
324ece8a530Spatrick };
325ece8a530Spatrick
326ece8a530Spatrick class UndefinedData : public DataSymbol {
327ece8a530Spatrick public:
328ece8a530Spatrick UndefinedData(StringRef name, uint32_t flags, InputFile *file = nullptr)
DataSymbol(name,UndefinedDataKind,flags,file)329ece8a530Spatrick : DataSymbol(name, UndefinedDataKind, flags, file) {}
classof(const Symbol * s)330ece8a530Spatrick static bool classof(const Symbol *s) {
331ece8a530Spatrick return s->kind() == UndefinedDataKind;
332ece8a530Spatrick }
333ece8a530Spatrick };
334ece8a530Spatrick
335ece8a530Spatrick class GlobalSymbol : public Symbol {
336ece8a530Spatrick public:
classof(const Symbol * s)337ece8a530Spatrick static bool classof(const Symbol *s) {
338ece8a530Spatrick return s->kind() == DefinedGlobalKind || s->kind() == UndefinedGlobalKind;
339ece8a530Spatrick }
340ece8a530Spatrick
getGlobalType()341ece8a530Spatrick const WasmGlobalType *getGlobalType() const { return globalType; }
342ece8a530Spatrick
343ece8a530Spatrick // Get/set the global index
344ece8a530Spatrick uint32_t getGlobalIndex() const;
345ece8a530Spatrick void setGlobalIndex(uint32_t index);
346ece8a530Spatrick bool hasGlobalIndex() const;
347ece8a530Spatrick
348ece8a530Spatrick protected:
GlobalSymbol(StringRef name,Kind k,uint32_t flags,InputFile * f,const WasmGlobalType * globalType)349ece8a530Spatrick GlobalSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
350ece8a530Spatrick const WasmGlobalType *globalType)
351ece8a530Spatrick : Symbol(name, k, flags, f), globalType(globalType) {}
352ece8a530Spatrick
353ece8a530Spatrick const WasmGlobalType *globalType;
354ece8a530Spatrick uint32_t globalIndex = INVALID_INDEX;
355ece8a530Spatrick };
356ece8a530Spatrick
357ece8a530Spatrick class DefinedGlobal : public GlobalSymbol {
358ece8a530Spatrick public:
359ece8a530Spatrick DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
360ece8a530Spatrick InputGlobal *global);
361ece8a530Spatrick
classof(const Symbol * s)362ece8a530Spatrick static bool classof(const Symbol *s) {
363ece8a530Spatrick return s->kind() == DefinedGlobalKind;
364ece8a530Spatrick }
365ece8a530Spatrick
366ece8a530Spatrick InputGlobal *global;
367ece8a530Spatrick };
368ece8a530Spatrick
369ece8a530Spatrick class UndefinedGlobal : public GlobalSymbol {
370ece8a530Spatrick public:
371*dfe94b16Srobert UndefinedGlobal(StringRef name, std::optional<StringRef> importName,
372*dfe94b16Srobert std::optional<StringRef> importModule, uint32_t flags,
373bb684c34Spatrick InputFile *file = nullptr,
374ece8a530Spatrick const WasmGlobalType *type = nullptr)
GlobalSymbol(name,UndefinedGlobalKind,flags,file,type)3751cf9926bSpatrick : GlobalSymbol(name, UndefinedGlobalKind, flags, file, type) {
3761cf9926bSpatrick this->importName = importName;
3771cf9926bSpatrick this->importModule = importModule;
3781cf9926bSpatrick }
379ece8a530Spatrick
classof(const Symbol * s)380ece8a530Spatrick static bool classof(const Symbol *s) {
381ece8a530Spatrick return s->kind() == UndefinedGlobalKind;
382ece8a530Spatrick }
383ece8a530Spatrick };
384ece8a530Spatrick
3851cf9926bSpatrick class TableSymbol : public Symbol {
386ece8a530Spatrick public:
classof(const Symbol * s)3871cf9926bSpatrick static bool classof(const Symbol *s) {
3881cf9926bSpatrick return s->kind() == DefinedTableKind || s->kind() == UndefinedTableKind;
3891cf9926bSpatrick }
390ece8a530Spatrick
getTableType()3911cf9926bSpatrick const WasmTableType *getTableType() const { return tableType; }
3921cf9926bSpatrick void setLimits(const WasmLimits &limits);
393ece8a530Spatrick
3941cf9926bSpatrick // Get/set the table number
3951cf9926bSpatrick uint32_t getTableNumber() const;
3961cf9926bSpatrick void setTableNumber(uint32_t number);
3971cf9926bSpatrick bool hasTableNumber() const;
3981cf9926bSpatrick
3991cf9926bSpatrick protected:
TableSymbol(StringRef name,Kind k,uint32_t flags,InputFile * f,const WasmTableType * type)4001cf9926bSpatrick TableSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
4011cf9926bSpatrick const WasmTableType *type)
4021cf9926bSpatrick : Symbol(name, k, flags, f), tableType(type) {}
4031cf9926bSpatrick
4041cf9926bSpatrick const WasmTableType *tableType;
4051cf9926bSpatrick uint32_t tableNumber = INVALID_INDEX;
4061cf9926bSpatrick };
4071cf9926bSpatrick
4081cf9926bSpatrick class DefinedTable : public TableSymbol {
4091cf9926bSpatrick public:
4101cf9926bSpatrick DefinedTable(StringRef name, uint32_t flags, InputFile *file,
4111cf9926bSpatrick InputTable *table);
4121cf9926bSpatrick
classof(const Symbol * s)4131cf9926bSpatrick static bool classof(const Symbol *s) { return s->kind() == DefinedTableKind; }
4141cf9926bSpatrick
4151cf9926bSpatrick InputTable *table;
4161cf9926bSpatrick };
4171cf9926bSpatrick
4181cf9926bSpatrick class UndefinedTable : public TableSymbol {
4191cf9926bSpatrick public:
UndefinedTable(StringRef name,std::optional<StringRef> importName,std::optional<StringRef> importModule,uint32_t flags,InputFile * file,const WasmTableType * type)420*dfe94b16Srobert UndefinedTable(StringRef name, std::optional<StringRef> importName,
421*dfe94b16Srobert std::optional<StringRef> importModule, uint32_t flags,
4221cf9926bSpatrick InputFile *file, const WasmTableType *type)
4231cf9926bSpatrick : TableSymbol(name, UndefinedTableKind, flags, file, type) {
4241cf9926bSpatrick this->importName = importName;
4251cf9926bSpatrick this->importModule = importModule;
4261cf9926bSpatrick }
4271cf9926bSpatrick
classof(const Symbol * s)4281cf9926bSpatrick static bool classof(const Symbol *s) {
4291cf9926bSpatrick return s->kind() == UndefinedTableKind;
4301cf9926bSpatrick }
4311cf9926bSpatrick };
4321cf9926bSpatrick
4331cf9926bSpatrick // A tag is a general format to distinguish typed entities. Each tag has an
4341cf9926bSpatrick // attribute and a type. Currently the attribute can only specify that the tag
4351cf9926bSpatrick // is for an exception tag.
4361cf9926bSpatrick //
4371cf9926bSpatrick // In exception handling, tags are used to distinguish different kinds of
4381cf9926bSpatrick // exceptions. For example, they can be used to distinguish different language's
4391cf9926bSpatrick // exceptions, e.g., all C++ exceptions have the same tag and Java exceptions
4401cf9926bSpatrick // would have a distinct tag. Wasm can filter the exceptions it catches based on
4411cf9926bSpatrick // their tag.
4421cf9926bSpatrick //
4431cf9926bSpatrick // A single TagSymbol object represents a single tag. The C++ exception symbol
4441cf9926bSpatrick // is a weak symbol generated in every object file in which exceptions are used,
4451cf9926bSpatrick // and is named '__cpp_exception' for linking.
4461cf9926bSpatrick class TagSymbol : public Symbol {
4471cf9926bSpatrick public:
classof(const Symbol * s)448*dfe94b16Srobert static bool classof(const Symbol *s) {
449*dfe94b16Srobert return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind;
450*dfe94b16Srobert }
4511cf9926bSpatrick
4521cf9926bSpatrick // Get/set the tag index
4531cf9926bSpatrick uint32_t getTagIndex() const;
4541cf9926bSpatrick void setTagIndex(uint32_t index);
4551cf9926bSpatrick bool hasTagIndex() const;
456ece8a530Spatrick
457ece8a530Spatrick const WasmSignature *signature;
458ece8a530Spatrick
459ece8a530Spatrick protected:
TagSymbol(StringRef name,Kind k,uint32_t flags,InputFile * f,const WasmSignature * sig)4601cf9926bSpatrick TagSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
461*dfe94b16Srobert const WasmSignature *sig)
462*dfe94b16Srobert : Symbol(name, k, flags, f), signature(sig) {}
463ece8a530Spatrick
4641cf9926bSpatrick uint32_t tagIndex = INVALID_INDEX;
465ece8a530Spatrick };
466ece8a530Spatrick
4671cf9926bSpatrick class DefinedTag : public TagSymbol {
468ece8a530Spatrick public:
4691cf9926bSpatrick DefinedTag(StringRef name, uint32_t flags, InputFile *file, InputTag *tag);
470ece8a530Spatrick
classof(const Symbol * s)4711cf9926bSpatrick static bool classof(const Symbol *s) { return s->kind() == DefinedTagKind; }
472ece8a530Spatrick
4731cf9926bSpatrick InputTag *tag;
474ece8a530Spatrick };
475ece8a530Spatrick
476*dfe94b16Srobert class UndefinedTag : public TagSymbol {
477*dfe94b16Srobert public:
478*dfe94b16Srobert UndefinedTag(StringRef name, std::optional<StringRef> importName,
479*dfe94b16Srobert std::optional<StringRef> importModule, uint32_t flags,
480*dfe94b16Srobert InputFile *file = nullptr, const WasmSignature *sig = nullptr)
TagSymbol(name,UndefinedTagKind,flags,file,sig)481*dfe94b16Srobert : TagSymbol(name, UndefinedTagKind, flags, file, sig) {
482*dfe94b16Srobert this->importName = importName;
483*dfe94b16Srobert this->importModule = importModule;
484*dfe94b16Srobert }
485*dfe94b16Srobert
classof(const Symbol * s)486*dfe94b16Srobert static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; }
487*dfe94b16Srobert };
488*dfe94b16Srobert
489ece8a530Spatrick // LazySymbol represents a symbol that is not yet in the link, but we know where
490ece8a530Spatrick // to find it if needed. If the resolver finds both Undefined and Lazy for the
491ece8a530Spatrick // same name, it will ask the Lazy to load a file.
492ece8a530Spatrick //
493ece8a530Spatrick // A special complication is the handling of weak undefined symbols. They should
494ece8a530Spatrick // not load a file, but we have to remember we have seen both the weak undefined
495ece8a530Spatrick // and the lazy. We represent that with a lazy symbol with a weak binding. This
496ece8a530Spatrick // means that code looking for undefined symbols normally also has to take lazy
497ece8a530Spatrick // symbols into consideration.
498ece8a530Spatrick class LazySymbol : public Symbol {
499ece8a530Spatrick public:
LazySymbol(StringRef name,uint32_t flags,InputFile * file,const llvm::object::Archive::Symbol & sym)500ece8a530Spatrick LazySymbol(StringRef name, uint32_t flags, InputFile *file,
501ece8a530Spatrick const llvm::object::Archive::Symbol &sym)
502ece8a530Spatrick : Symbol(name, LazyKind, flags, file), archiveSymbol(sym) {}
503ece8a530Spatrick
classof(const Symbol * s)504ece8a530Spatrick static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
505ece8a530Spatrick void fetch();
5061cf9926bSpatrick void setWeak();
507ece8a530Spatrick MemoryBufferRef getMemberBuffer();
508ece8a530Spatrick
509ece8a530Spatrick // Lazy symbols can have a signature because they can replace an
510*dfe94b16Srobert // UndefinedFunction in which case we need to be able to preserve the
511bb684c34Spatrick // signature.
512ece8a530Spatrick // TODO(sbc): This repetition of the signature field is inelegant. Revisit
513ece8a530Spatrick // the use of class hierarchy to represent symbol taxonomy.
514ece8a530Spatrick const WasmSignature *signature = nullptr;
515ece8a530Spatrick
516ece8a530Spatrick private:
517ece8a530Spatrick llvm::object::Archive::Symbol archiveSymbol;
518ece8a530Spatrick };
519ece8a530Spatrick
520ece8a530Spatrick // linker-generated symbols
521ece8a530Spatrick struct WasmSym {
522ece8a530Spatrick // __global_base
523ece8a530Spatrick // Symbol marking the start of the global section.
524ece8a530Spatrick static DefinedData *globalBase;
525ece8a530Spatrick
526*dfe94b16Srobert // __stack_pointer/__stack_low/__stack_high
527*dfe94b16Srobert // Global that holds current value of stack pointer and data symbols marking
528*dfe94b16Srobert // the start and end of the stack region. stackPointer is initialized to
529*dfe94b16Srobert // stackHigh and grows downwards towards stackLow
530ece8a530Spatrick static GlobalSymbol *stackPointer;
531*dfe94b16Srobert static DefinedData *stackLow;
532*dfe94b16Srobert static DefinedData *stackHigh;
533ece8a530Spatrick
534ece8a530Spatrick // __tls_base
535ece8a530Spatrick // Global that holds the address of the base of the current thread's
536ece8a530Spatrick // TLS block.
537ece8a530Spatrick static GlobalSymbol *tlsBase;
538ece8a530Spatrick
539ece8a530Spatrick // __tls_size
540ece8a530Spatrick // Symbol whose value is the size of the TLS block.
541ece8a530Spatrick static GlobalSymbol *tlsSize;
542ece8a530Spatrick
543ece8a530Spatrick // __tls_size
544ece8a530Spatrick // Symbol whose value is the alignment of the TLS block.
545ece8a530Spatrick static GlobalSymbol *tlsAlign;
546ece8a530Spatrick
547ece8a530Spatrick // __data_end
548ece8a530Spatrick // Symbol marking the end of the data and bss.
549ece8a530Spatrick static DefinedData *dataEnd;
550ece8a530Spatrick
551*dfe94b16Srobert // __heap_base/__heap_end
552*dfe94b16Srobert // Symbols marking the beginning and end of the "heap". It starts at the end
553*dfe94b16Srobert // of the data, bss and explicit stack, and extends to the end of the linear
554*dfe94b16Srobert // memory allocated by wasm-ld. This region of memory is not used by the
555*dfe94b16Srobert // linked code, so it may be used as a backing store for `sbrk` or `malloc`
556*dfe94b16Srobert // implementations.
557ece8a530Spatrick static DefinedData *heapBase;
558*dfe94b16Srobert static DefinedData *heapEnd;
559ece8a530Spatrick
560ece8a530Spatrick // __wasm_init_memory_flag
561ece8a530Spatrick // Symbol whose contents are nonzero iff memory has already been initialized.
562ece8a530Spatrick static DefinedData *initMemoryFlag;
563ece8a530Spatrick
564ece8a530Spatrick // __wasm_init_memory
565ece8a530Spatrick // Function that initializes passive data segments during instantiation.
566ece8a530Spatrick static DefinedFunction *initMemory;
567ece8a530Spatrick
568ece8a530Spatrick // __wasm_call_ctors
569ece8a530Spatrick // Function that directly calls all ctors in priority order.
570ece8a530Spatrick static DefinedFunction *callCtors;
571ece8a530Spatrick
5721cf9926bSpatrick // __wasm_call_dtors
5731cf9926bSpatrick // Function that calls the libc/etc. cleanup function.
5741cf9926bSpatrick static DefinedFunction *callDtors;
5751cf9926bSpatrick
5761cf9926bSpatrick // __wasm_apply_data_relocs
577ece8a530Spatrick // Function that applies relocations to data segment post-instantiation.
5781cf9926bSpatrick static DefinedFunction *applyDataRelocs;
5791cf9926bSpatrick
5801cf9926bSpatrick // __wasm_apply_global_relocs
581*dfe94b16Srobert // Function that applies relocations to wasm globals post-instantiation.
5821cf9926bSpatrick // Unlike __wasm_apply_data_relocs this needs to run on every thread.
5831cf9926bSpatrick static DefinedFunction *applyGlobalRelocs;
584ece8a530Spatrick
585*dfe94b16Srobert // __wasm_apply_global_tls_relocs
586*dfe94b16Srobert // Like applyGlobalRelocs but for globals that hold TLS addresses. These
587*dfe94b16Srobert // must be delayed until __wasm_init_tls.
588*dfe94b16Srobert static DefinedFunction *applyGlobalTLSRelocs;
589*dfe94b16Srobert
590ece8a530Spatrick // __wasm_init_tls
591ece8a530Spatrick // Function that allocates thread-local storage and initializes it.
592ece8a530Spatrick static DefinedFunction *initTLS;
593ece8a530Spatrick
5941cf9926bSpatrick // Pointer to the function that is to be used in the start section.
5951cf9926bSpatrick // (normally an alias of initMemory, or applyGlobalRelocs).
5961cf9926bSpatrick static DefinedFunction *startFunction;
5971cf9926bSpatrick
598ece8a530Spatrick // __dso_handle
599ece8a530Spatrick // Symbol used in calls to __cxa_atexit to determine current DLL
600ece8a530Spatrick static DefinedData *dsoHandle;
601ece8a530Spatrick
602ece8a530Spatrick // __table_base
603ece8a530Spatrick // Used in PIC code for offset of indirect function table
604ece8a530Spatrick static UndefinedGlobal *tableBase;
605ece8a530Spatrick static DefinedData *definedTableBase;
6061cf9926bSpatrick // 32-bit copy in wasm64 to work around init expr limitations.
6071cf9926bSpatrick // These can potentially be removed again once we have
6081cf9926bSpatrick // https://github.com/WebAssembly/extended-const
6091cf9926bSpatrick static UndefinedGlobal *tableBase32;
6101cf9926bSpatrick static DefinedData *definedTableBase32;
611ece8a530Spatrick
612ece8a530Spatrick // __memory_base
613ece8a530Spatrick // Used in PIC code for offset of global data
614ece8a530Spatrick static UndefinedGlobal *memoryBase;
615ece8a530Spatrick static DefinedData *definedMemoryBase;
6161cf9926bSpatrick
6171cf9926bSpatrick // __indirect_function_table
6181cf9926bSpatrick // Used as an address space for function pointers, with each function that is
6191cf9926bSpatrick // used as a function pointer being allocated a slot.
6201cf9926bSpatrick static TableSymbol *indirectFunctionTable;
621ece8a530Spatrick };
622ece8a530Spatrick
623ece8a530Spatrick // A buffer class that is large enough to hold any Symbol-derived
624ece8a530Spatrick // object. We allocate memory using this class and instantiate a symbol
625ece8a530Spatrick // using the placement new.
626ece8a530Spatrick union SymbolUnion {
627ece8a530Spatrick alignas(DefinedFunction) char a[sizeof(DefinedFunction)];
628ece8a530Spatrick alignas(DefinedData) char b[sizeof(DefinedData)];
629ece8a530Spatrick alignas(DefinedGlobal) char c[sizeof(DefinedGlobal)];
6301cf9926bSpatrick alignas(DefinedTag) char d[sizeof(DefinedTag)];
6311cf9926bSpatrick alignas(DefinedTable) char e[sizeof(DefinedTable)];
6321cf9926bSpatrick alignas(LazySymbol) char f[sizeof(LazySymbol)];
6331cf9926bSpatrick alignas(UndefinedFunction) char g[sizeof(UndefinedFunction)];
6341cf9926bSpatrick alignas(UndefinedData) char h[sizeof(UndefinedData)];
6351cf9926bSpatrick alignas(UndefinedGlobal) char i[sizeof(UndefinedGlobal)];
6361cf9926bSpatrick alignas(UndefinedTable) char j[sizeof(UndefinedTable)];
6371cf9926bSpatrick alignas(SectionSymbol) char k[sizeof(SectionSymbol)];
638ece8a530Spatrick };
639ece8a530Spatrick
640ece8a530Spatrick // It is important to keep the size of SymbolUnion small for performance and
641ece8a530Spatrick // memory usage reasons. 96 bytes is a soft limit based on the size of
642ece8a530Spatrick // UndefinedFunction on a 64-bit system.
6431cf9926bSpatrick static_assert(sizeof(SymbolUnion) <= 120, "SymbolUnion too large");
644ece8a530Spatrick
645ece8a530Spatrick void printTraceSymbol(Symbol *sym);
646ece8a530Spatrick void printTraceSymbolUndefined(StringRef name, const InputFile* file);
647ece8a530Spatrick
648ece8a530Spatrick template <typename T, typename... ArgT>
replaceSymbol(Symbol * s,ArgT &&...arg)649ece8a530Spatrick T *replaceSymbol(Symbol *s, ArgT &&... arg) {
650ece8a530Spatrick static_assert(std::is_trivially_destructible<T>(),
651ece8a530Spatrick "Symbol types must be trivially destructible");
652ece8a530Spatrick static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
653ece8a530Spatrick static_assert(alignof(T) <= alignof(SymbolUnion),
654ece8a530Spatrick "SymbolUnion not aligned enough");
655ece8a530Spatrick assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
656ece8a530Spatrick "Not a Symbol");
657ece8a530Spatrick
658ece8a530Spatrick Symbol symCopy = *s;
659ece8a530Spatrick
660ece8a530Spatrick T *s2 = new (s) T(std::forward<ArgT>(arg)...);
661ece8a530Spatrick s2->isUsedInRegularObj = symCopy.isUsedInRegularObj;
662ece8a530Spatrick s2->forceExport = symCopy.forceExport;
663*dfe94b16Srobert s2->forceImport = symCopy.forceImport;
664ece8a530Spatrick s2->canInline = symCopy.canInline;
665ece8a530Spatrick s2->traced = symCopy.traced;
666*dfe94b16Srobert s2->referenced = symCopy.referenced;
667ece8a530Spatrick
668ece8a530Spatrick // Print out a log message if --trace-symbol was specified.
669ece8a530Spatrick // This is for debugging.
670ece8a530Spatrick if (s2->traced)
671ece8a530Spatrick printTraceSymbol(s2);
672ece8a530Spatrick
673ece8a530Spatrick return s2;
674ece8a530Spatrick }
675ece8a530Spatrick
676ece8a530Spatrick } // namespace wasm
677ece8a530Spatrick
678ece8a530Spatrick // Returns a symbol name for an error message.
679ece8a530Spatrick std::string toString(const wasm::Symbol &sym);
680ece8a530Spatrick std::string toString(wasm::Symbol::Kind kind);
681ece8a530Spatrick std::string maybeDemangleSymbol(StringRef name);
682ece8a530Spatrick
683ece8a530Spatrick } // namespace lld
684ece8a530Spatrick
685ece8a530Spatrick #endif
686