1 //===- Symbols.h ------------------------------------------------*- C++ -*-===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef LLD_WASM_SYMBOLS_H
11 #define LLD_WASM_SYMBOLS_H
12 
13 #include "Config.h"
14 #include "lld/Common/LLVM.h"
15 #include "llvm/Object/Archive.h"
16 #include "llvm/Object/Wasm.h"
17 
18 namespace lld {
19 namespace wasm {
20 
21 using llvm::wasm::WasmSymbolType;
22 
23 class InputFile;
24 class InputChunk;
25 class InputSegment;
26 class InputFunction;
27 class InputGlobal;
28 class InputEvent;
29 class InputSection;
30 
31 #define INVALID_INDEX UINT32_MAX
32 
33 // The base class for real symbol classes.
34 class Symbol {
35 public:
36   enum Kind {
37     DefinedFunctionKind,
38     DefinedDataKind,
39     DefinedGlobalKind,
40     DefinedEventKind,
41     SectionKind,
42     UndefinedFunctionKind,
43     UndefinedDataKind,
44     UndefinedGlobalKind,
45     LazyKind,
46   };
47 
kind()48   Kind kind() const { return SymbolKind; }
49 
isDefined()50   bool isDefined() const {
51     return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind ||
52            SymbolKind == DefinedGlobalKind || SymbolKind == DefinedEventKind ||
53            SymbolKind == SectionKind;
54   }
55 
isUndefined()56   bool isUndefined() const {
57     return SymbolKind == UndefinedFunctionKind ||
58            SymbolKind == UndefinedDataKind || SymbolKind == UndefinedGlobalKind;
59   }
60 
isLazy()61   bool isLazy() const { return SymbolKind == LazyKind; }
62 
63   bool isLocal() const;
64   bool isWeak() const;
65   bool isHidden() const;
66 
67   // Returns the symbol name.
getName()68   StringRef getName() const { return Name; }
69 
70   // Returns the file from which this symbol was created.
getFile()71   InputFile *getFile() const { return File; }
72 
73   InputChunk *getChunk() const;
74 
75   // Indicates that the section or import for this symbol will be included in
76   // the final image.
77   bool isLive() const;
78 
79   // Marks the symbol's InputChunk as Live, so that it will be included in the
80   // final image.
81   void markLive();
82 
83   void setHidden(bool IsHidden);
84 
85   // Get/set the index in the output symbol table.  This is only used for
86   // relocatable output.
87   uint32_t getOutputSymbolIndex() const;
88   void setOutputSymbolIndex(uint32_t Index);
89 
90   WasmSymbolType getWasmType() const;
91   bool isExported() const;
92 
93   // True if this symbol was referenced by a regular (non-bitcode) object.
94   unsigned IsUsedInRegularObj : 1;
95   unsigned ForceExport : 1;
96 
97 protected:
Symbol(StringRef Name,Kind K,uint32_t Flags,InputFile * F)98   Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
99       : IsUsedInRegularObj(false), ForceExport(false), Name(Name),
100         SymbolKind(K), Flags(Flags), File(F), Referenced(!Config->GcSections) {}
101 
102   StringRef Name;
103   Kind SymbolKind;
104   uint32_t Flags;
105   InputFile *File;
106   uint32_t OutputSymbolIndex = INVALID_INDEX;
107   bool Referenced;
108 };
109 
110 class FunctionSymbol : public Symbol {
111 public:
classof(const Symbol * S)112   static bool classof(const Symbol *S) {
113     return S->kind() == DefinedFunctionKind ||
114            S->kind() == UndefinedFunctionKind;
115   }
116 
117   // Get/set the table index
118   void setTableIndex(uint32_t Index);
119   uint32_t getTableIndex() const;
120   bool hasTableIndex() const;
121 
122   // Get/set the function index
123   uint32_t getFunctionIndex() const;
124   void setFunctionIndex(uint32_t Index);
125   bool hasFunctionIndex() const;
126 
127   const WasmSignature *Signature;
128 
129 protected:
FunctionSymbol(StringRef Name,Kind K,uint32_t Flags,InputFile * F,const WasmSignature * Sig)130   FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
131                  const WasmSignature *Sig)
132       : Symbol(Name, K, Flags, F), Signature(Sig) {}
133 
134   uint32_t TableIndex = INVALID_INDEX;
135   uint32_t FunctionIndex = INVALID_INDEX;
136 };
137 
138 class DefinedFunction : public FunctionSymbol {
139 public:
140   DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
141                   InputFunction *Function);
142 
classof(const Symbol * S)143   static bool classof(const Symbol *S) {
144     return S->kind() == DefinedFunctionKind;
145   }
146 
147   InputFunction *Function;
148 };
149 
150 class UndefinedFunction : public FunctionSymbol {
151 public:
152   UndefinedFunction(StringRef Name, StringRef ImportName,
153                     StringRef ImportModule, uint32_t Flags,
154                     InputFile *File = nullptr,
155                     const WasmSignature *Type = nullptr)
FunctionSymbol(Name,UndefinedFunctionKind,Flags,File,Type)156       : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, Type),
157         ImportName(ImportName), ImportModule(ImportModule) {}
158 
classof(const Symbol * S)159   static bool classof(const Symbol *S) {
160     return S->kind() == UndefinedFunctionKind;
161   }
162 
163   StringRef ImportName;
164   StringRef ImportModule;
165 };
166 
167 class SectionSymbol : public Symbol {
168 public:
classof(const Symbol * S)169   static bool classof(const Symbol *S) { return S->kind() == SectionKind; }
170 
171   SectionSymbol(StringRef Name, uint32_t Flags, const InputSection *S,
172                 InputFile *F = nullptr)
Symbol(Name,SectionKind,Flags,F)173       : Symbol(Name, SectionKind, Flags, F), Section(S) {}
174 
175   const InputSection *Section;
176 
177   uint32_t getOutputSectionIndex() const;
178   void setOutputSectionIndex(uint32_t Index);
179 
180 protected:
181   uint32_t OutputSectionIndex = INVALID_INDEX;
182 };
183 
184 class DataSymbol : public Symbol {
185 public:
classof(const Symbol * S)186   static bool classof(const Symbol *S) {
187     return S->kind() == DefinedDataKind || S->kind() == UndefinedDataKind;
188   }
189 
190 protected:
DataSymbol(StringRef Name,Kind K,uint32_t Flags,InputFile * F)191   DataSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
192       : Symbol(Name, K, Flags, F) {}
193 };
194 
195 class DefinedData : public DataSymbol {
196 public:
197   // Constructor for regular data symbols originating from input files.
DefinedData(StringRef Name,uint32_t Flags,InputFile * F,InputSegment * Segment,uint32_t Offset,uint32_t Size)198   DefinedData(StringRef Name, uint32_t Flags, InputFile *F,
199               InputSegment *Segment, uint32_t Offset, uint32_t Size)
200       : DataSymbol(Name, DefinedDataKind, Flags, F), Segment(Segment),
201         Offset(Offset), Size(Size) {}
202 
203   // Constructor for linker synthetic data symbols.
DefinedData(StringRef Name,uint32_t Flags)204   DefinedData(StringRef Name, uint32_t Flags)
205       : DataSymbol(Name, DefinedDataKind, Flags, nullptr) {}
206 
classof(const Symbol * S)207   static bool classof(const Symbol *S) { return S->kind() == DefinedDataKind; }
208 
209   // Returns the output virtual address of a defined data symbol.
210   uint32_t getVirtualAddress() const;
211   void setVirtualAddress(uint32_t VA);
212 
213   // Returns the offset of a defined data symbol within its OutputSegment.
214   uint32_t getOutputSegmentOffset() const;
215   uint32_t getOutputSegmentIndex() const;
getSize()216   uint32_t getSize() const { return Size; }
217 
218   InputSegment *Segment = nullptr;
219 
220 protected:
221   uint32_t Offset = 0;
222   uint32_t Size = 0;
223 };
224 
225 class UndefinedData : public DataSymbol {
226 public:
227   UndefinedData(StringRef Name, uint32_t Flags, InputFile *File = nullptr)
DataSymbol(Name,UndefinedDataKind,Flags,File)228       : DataSymbol(Name, UndefinedDataKind, Flags, File) {}
classof(const Symbol * S)229   static bool classof(const Symbol *S) {
230     return S->kind() == UndefinedDataKind;
231   }
232 };
233 
234 class GlobalSymbol : public Symbol {
235 public:
classof(const Symbol * S)236   static bool classof(const Symbol *S) {
237     return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind;
238   }
239 
getGlobalType()240   const WasmGlobalType *getGlobalType() const { return GlobalType; }
241 
242   // Get/set the global index
243   uint32_t getGlobalIndex() const;
244   void setGlobalIndex(uint32_t Index);
245   bool hasGlobalIndex() const;
246 
247 protected:
GlobalSymbol(StringRef Name,Kind K,uint32_t Flags,InputFile * F,const WasmGlobalType * GlobalType)248   GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
249                const WasmGlobalType *GlobalType)
250       : Symbol(Name, K, Flags, F), GlobalType(GlobalType) {}
251 
252   const WasmGlobalType *GlobalType;
253   uint32_t GlobalIndex = INVALID_INDEX;
254 };
255 
256 class DefinedGlobal : public GlobalSymbol {
257 public:
258   DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
259                 InputGlobal *Global);
260 
classof(const Symbol * S)261   static bool classof(const Symbol *S) {
262     return S->kind() == DefinedGlobalKind;
263   }
264 
265   InputGlobal *Global;
266 };
267 
268 class UndefinedGlobal : public GlobalSymbol {
269 public:
270   UndefinedGlobal(StringRef Name, StringRef ImportName, StringRef ImportModule,
271                   uint32_t Flags, InputFile *File = nullptr,
272                   const WasmGlobalType *Type = nullptr)
GlobalSymbol(Name,UndefinedGlobalKind,Flags,File,Type)273       : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, Type),
274         ImportName(ImportName), ImportModule(ImportModule) {}
275 
classof(const Symbol * S)276   static bool classof(const Symbol *S) {
277     return S->kind() == UndefinedGlobalKind;
278   }
279 
280   StringRef ImportName;
281   StringRef ImportModule;
282 };
283 
284 // Wasm events are features that suspend the current execution and transfer the
285 // control flow to a corresponding handler. Currently the only supported event
286 // kind is exceptions.
287 //
288 // Event tags are values to distinguish different events. For exceptions, they
289 // can be used to distinguish different language's exceptions, i.e., all C++
290 // exceptions have the same tag. Wasm can generate code capable of doing
291 // different handling actions based on the tag of caught exceptions.
292 //
293 // A single EventSymbol object represents a single tag. C++ exception event
294 // symbol is a weak symbol generated in every object file in which exceptions
295 // are used, and has name '__cpp_exception' for linking.
296 class EventSymbol : public Symbol {
297 public:
classof(const Symbol * S)298   static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; }
299 
getEventType()300   const WasmEventType *getEventType() const { return EventType; }
301 
302   // Get/set the event index
303   uint32_t getEventIndex() const;
304   void setEventIndex(uint32_t Index);
305   bool hasEventIndex() const;
306 
307   const WasmSignature *Signature;
308 
309 protected:
EventSymbol(StringRef Name,Kind K,uint32_t Flags,InputFile * F,const WasmEventType * EventType,const WasmSignature * Sig)310   EventSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
311               const WasmEventType *EventType, const WasmSignature *Sig)
312       : Symbol(Name, K, Flags, F), Signature(Sig), EventType(EventType) {}
313 
314   const WasmEventType *EventType;
315   uint32_t EventIndex = INVALID_INDEX;
316 };
317 
318 class DefinedEvent : public EventSymbol {
319 public:
320   DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
321                InputEvent *Event);
322 
classof(const Symbol * S)323   static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; }
324 
325   InputEvent *Event;
326 };
327 
328 class LazySymbol : public Symbol {
329 public:
LazySymbol(StringRef Name,InputFile * File,const llvm::object::Archive::Symbol & Sym)330   LazySymbol(StringRef Name, InputFile *File,
331              const llvm::object::Archive::Symbol &Sym)
332       : Symbol(Name, LazyKind, 0, File), ArchiveSymbol(Sym) {}
333 
classof(const Symbol * S)334   static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
335   void fetch();
336 
337 private:
338   llvm::object::Archive::Symbol ArchiveSymbol;
339 };
340 
341 // linker-generated symbols
342 struct WasmSym {
343   // __stack_pointer
344   // Global that holds the address of the top of the explicit value stack in
345   // linear memory.
346   static GlobalSymbol *StackPointer;
347 
348   // __data_end
349   // Symbol marking the end of the data and bss.
350   static DefinedData *DataEnd;
351 
352   // __heap_base
353   // Symbol marking the end of the data, bss and explicit stack.  Any linear
354   // memory following this address is not used by the linked code and can
355   // therefore be used as a backing store for brk()/malloc() implementations.
356   static DefinedData *HeapBase;
357 
358   // __wasm_call_ctors
359   // Function that directly calls all ctors in priority order.
360   static DefinedFunction *CallCtors;
361 
362   // __dso_handle
363   // Symbol used in calls to __cxa_atexit to determine current DLL
364   static DefinedData *DsoHandle;
365 
366   // __table_base
367   // Used in PIC code for offset of indirect function table
368   static UndefinedGlobal *TableBase;
369 
370   // __memory_base
371   // Used in PIC code for offset of global data
372   static UndefinedGlobal *MemoryBase;
373 };
374 
375 // A buffer class that is large enough to hold any Symbol-derived
376 // object. We allocate memory using this class and instantiate a symbol
377 // using the placement new.
378 union SymbolUnion {
379   alignas(DefinedFunction) char A[sizeof(DefinedFunction)];
380   alignas(DefinedData) char B[sizeof(DefinedData)];
381   alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)];
382   alignas(DefinedEvent) char D[sizeof(DefinedEvent)];
383   alignas(LazySymbol) char E[sizeof(LazySymbol)];
384   alignas(UndefinedFunction) char F[sizeof(UndefinedFunction)];
385   alignas(UndefinedData) char G[sizeof(UndefinedData)];
386   alignas(UndefinedGlobal) char H[sizeof(UndefinedGlobal)];
387   alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
388 };
389 
390 template <typename T, typename... ArgT>
replaceSymbol(Symbol * S,ArgT &&...Arg)391 T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
392   static_assert(std::is_trivially_destructible<T>(),
393                 "Symbol types must be trivially destructible");
394   static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
395   static_assert(alignof(T) <= alignof(SymbolUnion),
396                 "SymbolUnion not aligned enough");
397   assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
398          "Not a Symbol");
399 
400   Symbol SymCopy = *S;
401 
402   T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
403   S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
404   S2->ForceExport = SymCopy.ForceExport;
405   return S2;
406 }
407 
408 } // namespace wasm
409 
410 // Returns a symbol name for an error message.
411 std::string toString(const wasm::Symbol &Sym);
412 std::string toString(wasm::Symbol::Kind Kind);
413 std::string maybeDemangleSymbol(StringRef Name);
414 
415 } // namespace lld
416 
417 #endif
418