1//===- Symbols.h ------------------------------------------------*- C++ -*-===//
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#ifndef LLD_WASM_SYMBOLS_H
10#define LLD_WASM_SYMBOLS_H
11
12#include "Config.h"
13#include "lld/Common/LLVM.h"
14#include "llvm/Object/Archive.h"
15#include "llvm/Object/Wasm.h"
16#include <optional>
17
18namespace lld {
19namespace wasm {
20
21// Shared string constants
22
23// The default module name to use for symbol imports.
24extern const char *defaultModule;
25
26// The name under which to import or export the wasm table.
27extern const char *functionTableName;
28
29// The name under which to import or export the wasm memory.
30extern const char *memoryName;
31
32using llvm::wasm::WasmSymbolType;
33
34class InputFile;
35class InputChunk;
36class InputSegment;
37class InputFunction;
38class InputGlobal;
39class InputTag;
40class InputSection;
41class InputTable;
42class OutputSection;
43
44#define INVALID_INDEX UINT32_MAX
45
46// The base class for real symbol classes.
47class Symbol {
48public:
49 enum Kind : uint8_t {
50 DefinedFunctionKind,
51 DefinedDataKind,
52 DefinedGlobalKind,
53 DefinedTagKind,
54 DefinedTableKind,
55 SectionKind,
56 OutputSectionKind,
57 UndefinedFunctionKind,
58 UndefinedDataKind,
59 UndefinedGlobalKind,
60 UndefinedTableKind,
61 UndefinedTagKind,
62 LazyKind,
63 SharedFunctionKind,
64 SharedDataKind,
65 };
66
67 Kind kind() const { return symbolKind; }
68
69 bool isDefined() const { return !isLazy() && !isUndefined(); }
70
71 bool isUndefined() const {
72 return symbolKind == UndefinedFunctionKind ||
73 symbolKind == UndefinedDataKind ||
74 symbolKind == UndefinedGlobalKind ||
75 symbolKind == UndefinedTableKind || symbolKind == UndefinedTagKind;
76 }
77
78 bool isLazy() const { return symbolKind == LazyKind; }
79 bool isShared() const {
80 return symbolKind == SharedFunctionKind || symbolKind == SharedDataKind;
81 }
82
83 bool isLocal() const;
84 bool isWeak() const;
85 bool isHidden() const;
86 bool isTLS() const;
87
88 // Returns true if this symbol exists in a discarded (due to COMDAT) section
89 bool isDiscarded() const;
90
91 // True if this is an undefined weak symbol. This only works once
92 // all input files have been added.
93 bool isUndefWeak() const {
94 // See comment on lazy symbols for details.
95 return isWeak() && (isUndefined() || isLazy());
96 }
97
98 // Returns the symbol name.
99 StringRef getName() const { return name; }
100
101 // Returns the file from which this symbol was created.
102 InputFile *getFile() const { return file; }
103
104 InputChunk *getChunk() const;
105
106 // Indicates that the section or import for this symbol will be included in
107 // the final image.
108 bool isLive() const;
109
110 // Marks the symbol's InputChunk as Live, so that it will be included in the
111 // final image.
112 void markLive();
113
114 void setHidden(bool isHidden);
115
116 // Get/set the index in the output symbol table. This is only used for
117 // relocatable output.
118 uint32_t getOutputSymbolIndex() const;
119 void setOutputSymbolIndex(uint32_t index);
120
121 WasmSymbolType getWasmType() const;
122 bool isImported() const;
123 bool isExported() const;
124 bool isExportedExplicit() const;
125
126 // Indicates that the symbol is used in an __attribute__((used)) directive
127 // or similar.
128 bool isNoStrip() const;
129
130 const WasmSignature* getSignature() const;
131
132 uint32_t getGOTIndex() const {
133 assert(gotIndex != INVALID_INDEX);
134 return gotIndex;
135 }
136
137 void setGOTIndex(uint32_t index);
138 bool hasGOTIndex() const { return gotIndex != INVALID_INDEX; }
139
140protected:
141 Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
142 : name(name), file(f), symbolKind(k), referenced(!ctx.arg.gcSections),
143 requiresGOT(false), isUsedInRegularObj(false), forceExport(false),
144 forceImport(false), canInline(false), traced(false), isStub(false),
145 flags(flags) {}
146
147 StringRef name;
148 InputFile *file;
149 uint32_t outputSymbolIndex = INVALID_INDEX;
150 uint32_t gotIndex = INVALID_INDEX;
151 Kind symbolKind;
152
153public:
154 bool referenced : 1;
155
156 // True for data symbols that needs a dummy GOT entry. Used for static
157 // linking of GOT accesses.
158 bool requiresGOT : 1;
159
160 // True if the symbol was used for linking and thus need to be added to the
161 // output file's symbol table. This is true for all symbols except for
162 // unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that
163 // are unreferenced except by other bitcode objects.
164 bool isUsedInRegularObj : 1;
165
166 // True if this symbol is explicitly marked for export (i.e. via the
167 // -e/--export command line flag)
168 bool forceExport : 1;
169
170 bool forceImport : 1;
171
172 // False if LTO shouldn't inline whatever this symbol points to. If a symbol
173 // is overwritten after LTO, LTO shouldn't inline the symbol because it
174 // doesn't know the final contents of the symbol.
175 bool canInline : 1;
176
177 // True if this symbol is specified by --trace-symbol option.
178 bool traced : 1;
179
180 // True if this symbol is a linker-synthesized stub function (traps when
181 // called) and should otherwise be treated as missing/undefined. See
182 // SymbolTable::replaceWithUndefined.
183 // These stubs never appear in the table and any table index relocations
184 // against them will produce address 0 (The table index representing
185 // the null function pointer).
186 bool isStub : 1;
187
188 uint32_t flags;
189
190 std::optional<StringRef> importName;
191 std::optional<StringRef> importModule;
192};
193
194class FunctionSymbol : public Symbol {
195public:
196 static bool classof(const Symbol *s) {
197 return s->kind() == DefinedFunctionKind ||
198 s->kind() == SharedFunctionKind ||
199 s->kind() == UndefinedFunctionKind;
200 }
201
202 // Get/set the table index
203 void setTableIndex(uint32_t index);
204 uint32_t getTableIndex() const;
205 bool hasTableIndex() const;
206
207 // Get/set the function index
208 uint32_t getFunctionIndex() const;
209 void setFunctionIndex(uint32_t index);
210 bool hasFunctionIndex() const;
211
212 const WasmSignature *signature;
213
214protected:
215 FunctionSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
216 const WasmSignature *sig)
217 : Symbol(name, k, flags, f), signature(sig) {}
218
219 uint32_t tableIndex = INVALID_INDEX;
220 uint32_t functionIndex = INVALID_INDEX;
221};
222
223class DefinedFunction : public FunctionSymbol {
224public:
225 DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
226 InputFunction *function);
227
228 static bool classof(const Symbol *s) {
229 return s->kind() == DefinedFunctionKind;
230 }
231
232 // Get the function index to be used when exporting. This only applies to
233 // defined functions and can be differ from the regular function index for
234 // weakly defined functions (that are imported and used via one index but
235 // defined and exported via another).
236 uint32_t getExportedFunctionIndex() const;
237
238 InputFunction *function;
239};
240
241class UndefinedFunction : public FunctionSymbol {
242public:
243 UndefinedFunction(StringRef name, std::optional<StringRef> importName,
244 std::optional<StringRef> importModule, uint32_t flags,
245 InputFile *file = nullptr,
246 const WasmSignature *type = nullptr,
247 bool isCalledDirectly = true)
248 : FunctionSymbol(name, UndefinedFunctionKind, flags, file, type),
249 isCalledDirectly(isCalledDirectly) {
250 this->importName = importName;
251 this->importModule = importModule;
252 }
253
254 static bool classof(const Symbol *s) {
255 return s->kind() == UndefinedFunctionKind;
256 }
257
258 DefinedFunction *stubFunction = nullptr;
259 bool isCalledDirectly;
260};
261
262// Section symbols for output sections are different from those for input
263// section. These are generated by the linker and point the OutputSection
264// rather than an InputSection.
265class OutputSectionSymbol : public Symbol {
266public:
267 OutputSectionSymbol(const OutputSection *s)
268 : Symbol("", OutputSectionKind, llvm::wasm::WASM_SYMBOL_BINDING_LOCAL,
269 nullptr),
270 section(s) {}
271
272 static bool classof(const Symbol *s) {
273 return s->kind() == OutputSectionKind;
274 }
275
276 const OutputSection *section;
277};
278
279class SectionSymbol : public Symbol {
280public:
281 SectionSymbol(uint32_t flags, const InputChunk *s, InputFile *f = nullptr)
282 : Symbol("", SectionKind, flags, f), section(s) {}
283
284 static bool classof(const Symbol *s) { return s->kind() == SectionKind; }
285
286 const OutputSectionSymbol *getOutputSectionSymbol() const;
287
288 const InputChunk *section;
289};
290
291class DataSymbol : public Symbol {
292public:
293 static bool classof(const Symbol *s) {
294 return s->kind() == DefinedDataKind || s->kind() == UndefinedDataKind ||
295 s->kind() == SharedDataKind;
296 }
297
298protected:
299 DataSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
300 : Symbol(name, k, flags, f) {}
301};
302
303class DefinedData : public DataSymbol {
304public:
305 // Constructor for regular data symbols originating from input files.
306 DefinedData(StringRef name, uint32_t flags, InputFile *f, InputChunk *segment,
307 uint64_t value, uint64_t size)
308 : DataSymbol(name, DefinedDataKind, flags, f), segment(segment),
309 value(value), size(size) {}
310
311 // Constructor for linker synthetic data symbols.
312 DefinedData(StringRef name, uint32_t flags)
313 : DataSymbol(name, DefinedDataKind, flags, nullptr) {}
314
315 static bool classof(const Symbol *s) { return s->kind() == DefinedDataKind; }
316
317 // Returns the output virtual address of a defined data symbol.
318 // For TLS symbols, by default (unless absolute is set), this returns an
319 // address relative the `__tls_base`.
320 uint64_t getVA(bool absolute = false) const;
321 void setVA(uint64_t va);
322
323 // Returns the offset of a defined data symbol within its OutputSegment.
324 uint64_t getOutputSegmentOffset() const;
325 uint64_t getOutputSegmentIndex() const;
326 uint64_t getSize() const { return size; }
327
328 InputChunk *segment = nullptr;
329 uint64_t value = 0;
330
331protected:
332 uint64_t size = 0;
333};
334
335class SharedData : public DataSymbol {
336public:
337 SharedData(StringRef name, uint32_t flags, InputFile *f)
338 : DataSymbol(name, SharedDataKind, flags, f) {}
339};
340
341class UndefinedData : public DataSymbol {
342public:
343 UndefinedData(StringRef name, uint32_t flags, InputFile *file = nullptr)
344 : DataSymbol(name, UndefinedDataKind, flags, file) {}
345 static bool classof(const Symbol *s) {
346 return s->kind() == UndefinedDataKind;
347 }
348};
349
350class GlobalSymbol : public Symbol {
351public:
352 static bool classof(const Symbol *s) {
353 return s->kind() == DefinedGlobalKind || s->kind() == UndefinedGlobalKind;
354 }
355
356 const WasmGlobalType *getGlobalType() const { return globalType; }
357
358 // Get/set the global index
359 uint32_t getGlobalIndex() const;
360 void setGlobalIndex(uint32_t index);
361 bool hasGlobalIndex() const;
362
363protected:
364 GlobalSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
365 const WasmGlobalType *globalType)
366 : Symbol(name, k, flags, f), globalType(globalType) {}
367
368 const WasmGlobalType *globalType;
369 uint32_t globalIndex = INVALID_INDEX;
370};
371
372class DefinedGlobal : public GlobalSymbol {
373public:
374 DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
375 InputGlobal *global);
376
377 static bool classof(const Symbol *s) {
378 return s->kind() == DefinedGlobalKind;
379 }
380
381 InputGlobal *global;
382};
383
384class UndefinedGlobal : public GlobalSymbol {
385public:
386 UndefinedGlobal(StringRef name, std::optional<StringRef> importName,
387 std::optional<StringRef> importModule, uint32_t flags,
388 InputFile *file = nullptr,
389 const WasmGlobalType *type = nullptr)
390 : GlobalSymbol(name, UndefinedGlobalKind, flags, file, type) {
391 this->importName = importName;
392 this->importModule = importModule;
393 }
394
395 static bool classof(const Symbol *s) {
396 return s->kind() == UndefinedGlobalKind;
397 }
398};
399
400class TableSymbol : public Symbol {
401public:
402 static bool classof(const Symbol *s) {
403 return s->kind() == DefinedTableKind || s->kind() == UndefinedTableKind;
404 }
405
406 const WasmTableType *getTableType() const { return tableType; }
407 void setLimits(const WasmLimits &limits);
408
409 // Get/set the table number
410 uint32_t getTableNumber() const;
411 void setTableNumber(uint32_t number);
412 bool hasTableNumber() const;
413
414protected:
415 TableSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
416 const WasmTableType *type)
417 : Symbol(name, k, flags, f), tableType(type) {}
418
419 const WasmTableType *tableType;
420 uint32_t tableNumber = INVALID_INDEX;
421};
422
423class DefinedTable : public TableSymbol {
424public:
425 DefinedTable(StringRef name, uint32_t flags, InputFile *file,
426 InputTable *table);
427
428 static bool classof(const Symbol *s) { return s->kind() == DefinedTableKind; }
429
430 InputTable *table;
431};
432
433class UndefinedTable : public TableSymbol {
434public:
435 UndefinedTable(StringRef name, std::optional<StringRef> importName,
436 std::optional<StringRef> importModule, uint32_t flags,
437 InputFile *file, const WasmTableType *type)
438 : TableSymbol(name, UndefinedTableKind, flags, file, type) {
439 this->importName = importName;
440 this->importModule = importModule;
441 }
442
443 static bool classof(const Symbol *s) {
444 return s->kind() == UndefinedTableKind;
445 }
446};
447
448// A tag is a general format to distinguish typed entities. Each tag has an
449// attribute and a type. Currently the attribute can only specify that the tag
450// is for an exception tag.
451//
452// In exception handling, tags are used to distinguish different kinds of
453// exceptions. For example, they can be used to distinguish different language's
454// exceptions, e.g., all C++ exceptions have the same tag and Java exceptions
455// would have a distinct tag. Wasm can filter the exceptions it catches based on
456// their tag.
457//
458// A single TagSymbol object represents a single tag. The C++ exception symbol
459// is a weak symbol generated in every object file in which exceptions are used,
460// and is named '__cpp_exception' for linking.
461class TagSymbol : public Symbol {
462public:
463 static bool classof(const Symbol *s) {
464 return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind;
465 }
466
467 // Get/set the tag index
468 uint32_t getTagIndex() const;
469 void setTagIndex(uint32_t index);
470 bool hasTagIndex() const;
471
472 const WasmSignature *signature;
473
474protected:
475 TagSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
476 const WasmSignature *sig)
477 : Symbol(name, k, flags, f), signature(sig) {}
478
479 uint32_t tagIndex = INVALID_INDEX;
480};
481
482class DefinedTag : public TagSymbol {
483public:
484 DefinedTag(StringRef name, uint32_t flags, InputFile *file, InputTag *tag);
485
486 static bool classof(const Symbol *s) { return s->kind() == DefinedTagKind; }
487
488 InputTag *tag;
489};
490
491class UndefinedTag : public TagSymbol {
492public:
493 UndefinedTag(StringRef name, std::optional<StringRef> importName,
494 std::optional<StringRef> importModule, uint32_t flags,
495 InputFile *file = nullptr, const WasmSignature *sig = nullptr)
496 : TagSymbol(name, UndefinedTagKind, flags, file, sig) {
497 this->importName = importName;
498 this->importModule = importModule;
499 }
500
501 static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; }
502};
503
504class SharedFunctionSymbol : public FunctionSymbol {
505public:
506 SharedFunctionSymbol(StringRef name, uint32_t flags, InputFile *file,
507 const WasmSignature *sig)
508 : FunctionSymbol(name, SharedFunctionKind, flags, file, sig) {}
509 static bool classof(const Symbol *s) {
510 return s->kind() == SharedFunctionKind;
511 }
512};
513
514// LazySymbol symbols represent symbols in object files between --start-lib and
515// --end-lib options. LLD also handles traditional archives as if all the files
516// in the archive are surrounded by --start-lib and --end-lib.
517//
518// A special complication is the handling of weak undefined symbols. They should
519// not load a file, but we have to remember we have seen both the weak undefined
520// and the lazy. We represent that with a lazy symbol with a weak binding. This
521// means that code looking for undefined symbols normally also has to take lazy
522// symbols into consideration.
523class LazySymbol : public Symbol {
524public:
525 LazySymbol(StringRef name, uint32_t flags, InputFile *file)
526 : Symbol(name, LazyKind, flags, file) {}
527
528 static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
529 void extract();
530 void setWeak();
531
532 // Lazy symbols can have a signature because they can replace an
533 // UndefinedFunction in which case we need to be able to preserve the
534 // signature.
535 // TODO(sbc): This repetition of the signature field is inelegant. Revisit
536 // the use of class hierarchy to represent symbol taxonomy.
537 const WasmSignature *signature = nullptr;
538};
539
540// A buffer class that is large enough to hold any Symbol-derived
541// object. We allocate memory using this class and instantiate a symbol
542// using the placement new.
543union SymbolUnion {
544 alignas(DefinedFunction) char a[sizeof(DefinedFunction)];
545 alignas(DefinedData) char b[sizeof(DefinedData)];
546 alignas(DefinedGlobal) char c[sizeof(DefinedGlobal)];
547 alignas(DefinedTag) char d[sizeof(DefinedTag)];
548 alignas(DefinedTable) char e[sizeof(DefinedTable)];
549 alignas(LazySymbol) char f[sizeof(LazySymbol)];
550 alignas(UndefinedFunction) char g[sizeof(UndefinedFunction)];
551 alignas(UndefinedData) char h[sizeof(UndefinedData)];
552 alignas(UndefinedGlobal) char i[sizeof(UndefinedGlobal)];
553 alignas(UndefinedTable) char j[sizeof(UndefinedTable)];
554 alignas(SectionSymbol) char k[sizeof(SectionSymbol)];
555 alignas(SharedFunctionSymbol) char l[sizeof(SharedFunctionSymbol)];
556};
557
558// It is important to keep the size of SymbolUnion small for performance and
559// memory usage reasons. 96 bytes is a soft limit based on the size of
560// UndefinedFunction on a 64-bit system.
561static_assert(sizeof(SymbolUnion) <= 120, "SymbolUnion too large");
562
563void printTraceSymbol(Symbol *sym);
564void printTraceSymbolUndefined(StringRef name, const InputFile* file);
565
566template <typename T, typename... ArgT>
567T *replaceSymbol(Symbol *s, ArgT &&... arg) {
568 static_assert(std::is_trivially_destructible<T>(),
569 "Symbol types must be trivially destructible");
570 static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
571 static_assert(alignof(T) <= alignof(SymbolUnion),
572 "SymbolUnion not aligned enough");
573 assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
574 "Not a Symbol");
575
576 Symbol symCopy = *s;
577
578 T *s2 = new (s) T(std::forward<ArgT>(arg)...);
579 s2->isUsedInRegularObj = symCopy.isUsedInRegularObj;
580 s2->forceExport = symCopy.forceExport;
581 s2->forceImport = symCopy.forceImport;
582 s2->canInline = symCopy.canInline;
583 s2->traced = symCopy.traced;
584 s2->referenced = symCopy.referenced;
585
586 // Print out a log message if --trace-symbol was specified.
587 // This is for debugging.
588 if (s2->traced)
589 printTraceSymbol(s2);
590
591 return s2;
592}
593
594} // namespace wasm
595
596// Returns a symbol name for an error message.
597std::string toString(const wasm::Symbol &sym);
598std::string toString(wasm::Symbol::Kind kind);
599std::string maybeDemangleSymbol(StringRef name);
600
601} // namespace lld
602
603#endif
604

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of lld/wasm/Symbols.h