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