xref: /llvm-project-15.0.7/lld/wasm/Symbols.cpp (revision 303c9861)
1 //===- Symbols.cpp --------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Symbols.h"
10 #include "Config.h"
11 #include "InputChunks.h"
12 #include "InputEvent.h"
13 #include "InputFiles.h"
14 #include "InputGlobal.h"
15 #include "OutputSections.h"
16 #include "OutputSegment.h"
17 #include "lld/Common/ErrorHandler.h"
18 #include "lld/Common/Strings.h"
19 
20 #define DEBUG_TYPE "lld"
21 
22 using namespace llvm;
23 using namespace llvm::wasm;
24 using namespace lld;
25 using namespace lld::wasm;
26 
27 DefinedFunction *WasmSym::CallCtors;
28 DefinedFunction *WasmSym::ApplyRelocs;
29 DefinedData *WasmSym::DsoHandle;
30 DefinedData *WasmSym::DataEnd;
31 DefinedData *WasmSym::HeapBase;
32 GlobalSymbol *WasmSym::StackPointer;
33 UndefinedGlobal *WasmSym::TableBase;
34 UndefinedGlobal *WasmSym::MemoryBase;
35 
36 WasmSymbolType Symbol::getWasmType() const {
37   if (isa<FunctionSymbol>(this))
38     return WASM_SYMBOL_TYPE_FUNCTION;
39   if (isa<DataSymbol>(this))
40     return WASM_SYMBOL_TYPE_DATA;
41   if (isa<GlobalSymbol>(this))
42     return WASM_SYMBOL_TYPE_GLOBAL;
43   if (isa<EventSymbol>(this))
44     return WASM_SYMBOL_TYPE_EVENT;
45   if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))
46     return WASM_SYMBOL_TYPE_SECTION;
47   llvm_unreachable("invalid symbol kind");
48 }
49 
50 const WasmSignature *Symbol::getSignature() const {
51   if (auto* F = dyn_cast<FunctionSymbol>(this))
52     return F->Signature;
53   if (auto *L = dyn_cast<LazySymbol>(this))
54     return L->Signature;
55   return nullptr;
56 }
57 
58 InputChunk *Symbol::getChunk() const {
59   if (auto *F = dyn_cast<DefinedFunction>(this))
60     return F->Function;
61   if (auto *D = dyn_cast<DefinedData>(this))
62     return D->Segment;
63   return nullptr;
64 }
65 
66 bool Symbol::isDiscarded() const {
67   if (InputChunk *C = getChunk())
68     return C->Discarded;
69   return false;
70 }
71 
72 bool Symbol::isLive() const {
73   if (auto *G = dyn_cast<DefinedGlobal>(this))
74     return G->Global->Live;
75   if (auto *E = dyn_cast<DefinedEvent>(this))
76     return E->Event->Live;
77   if (InputChunk *C = getChunk())
78     return C->Live;
79   return Referenced;
80 }
81 
82 void Symbol::markLive() {
83   assert(!isDiscarded());
84   if (auto *G = dyn_cast<DefinedGlobal>(this))
85     G->Global->Live = true;
86   if (auto *E = dyn_cast<DefinedEvent>(this))
87     E->Event->Live = true;
88   if (InputChunk *C = getChunk())
89     C->Live = true;
90   Referenced = true;
91 }
92 
93 uint32_t Symbol::getOutputSymbolIndex() const {
94   assert(OutputSymbolIndex != INVALID_INDEX);
95   return OutputSymbolIndex;
96 }
97 
98 void Symbol::setOutputSymbolIndex(uint32_t Index) {
99   LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index
100                     << "\n");
101   assert(OutputSymbolIndex == INVALID_INDEX);
102   OutputSymbolIndex = Index;
103 }
104 
105 void Symbol::setGOTIndex(uint32_t Index) {
106   LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n");
107   assert(GOTIndex == INVALID_INDEX);
108   // Any symbol that is assigned a GOT entry must be exported othewise the
109   // dynamic linker won't be able create the entry that contains it.
110   ForceExport = true;
111   GOTIndex = Index;
112 }
113 
114 bool Symbol::isWeak() const {
115   return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
116 }
117 
118 bool Symbol::isLocal() const {
119   return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
120 }
121 
122 bool Symbol::isHidden() const {
123   return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
124 }
125 
126 void Symbol::setHidden(bool IsHidden) {
127   LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");
128   Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
129   if (IsHidden)
130     Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
131   else
132     Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
133 }
134 
135 bool Symbol::isExported() const {
136   if (!isDefined() || isLocal())
137     return false;
138 
139   if (ForceExport || Config->ExportAll)
140     return true;
141 
142   if (Config->ExportDynamic && !isHidden())
143     return true;
144 
145   return Flags & WASM_SYMBOL_EXPORTED;
146 }
147 
148 uint32_t FunctionSymbol::getFunctionIndex() const {
149   if (auto *F = dyn_cast<DefinedFunction>(this))
150     return F->Function->getFunctionIndex();
151   assert(FunctionIndex != INVALID_INDEX);
152   return FunctionIndex;
153 }
154 
155 void FunctionSymbol::setFunctionIndex(uint32_t Index) {
156   LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n");
157   assert(FunctionIndex == INVALID_INDEX);
158   FunctionIndex = Index;
159 }
160 
161 bool FunctionSymbol::hasFunctionIndex() const {
162   if (auto *F = dyn_cast<DefinedFunction>(this))
163     return F->Function->hasFunctionIndex();
164   return FunctionIndex != INVALID_INDEX;
165 }
166 
167 uint32_t FunctionSymbol::getTableIndex() const {
168   if (auto *F = dyn_cast<DefinedFunction>(this))
169     return F->Function->getTableIndex();
170   assert(TableIndex != INVALID_INDEX);
171   return TableIndex;
172 }
173 
174 bool FunctionSymbol::hasTableIndex() const {
175   if (auto *F = dyn_cast<DefinedFunction>(this))
176     return F->Function->hasTableIndex();
177   return TableIndex != INVALID_INDEX;
178 }
179 
180 void FunctionSymbol::setTableIndex(uint32_t Index) {
181   // For imports, we set the table index here on the Symbol; for defined
182   // functions we set the index on the InputFunction so that we don't export
183   // the same thing twice (keeps the table size down).
184   if (auto *F = dyn_cast<DefinedFunction>(this)) {
185     F->Function->setTableIndex(Index);
186     return;
187   }
188   LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
189   assert(TableIndex == INVALID_INDEX);
190   TableIndex = Index;
191 }
192 
193 DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
194                                  InputFunction *Function)
195     : FunctionSymbol(Name, DefinedFunctionKind, Flags, F,
196                      Function ? &Function->Signature : nullptr),
197       Function(Function) {}
198 
199 uint32_t DefinedData::getVirtualAddress() const {
200   LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
201   if (Segment)
202     return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset;
203   return Offset;
204 }
205 
206 void DefinedData::setVirtualAddress(uint32_t Value) {
207   LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
208   assert(!Segment);
209   Offset = Value;
210 }
211 
212 uint32_t DefinedData::getOutputSegmentOffset() const {
213   LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
214   return Segment->OutputSegmentOffset + Offset;
215 }
216 
217 uint32_t DefinedData::getOutputSegmentIndex() const {
218   LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
219   return Segment->OutputSeg->Index;
220 }
221 
222 uint32_t GlobalSymbol::getGlobalIndex() const {
223   if (auto *F = dyn_cast<DefinedGlobal>(this))
224     return F->Global->getGlobalIndex();
225   assert(GlobalIndex != INVALID_INDEX);
226   return GlobalIndex;
227 }
228 
229 void GlobalSymbol::setGlobalIndex(uint32_t Index) {
230   LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n");
231   assert(GlobalIndex == INVALID_INDEX);
232   GlobalIndex = Index;
233 }
234 
235 bool GlobalSymbol::hasGlobalIndex() const {
236   if (auto *F = dyn_cast<DefinedGlobal>(this))
237     return F->Global->hasGlobalIndex();
238   return GlobalIndex != INVALID_INDEX;
239 }
240 
241 DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
242                              InputGlobal *Global)
243     : GlobalSymbol(Name, DefinedGlobalKind, Flags, File,
244                    Global ? &Global->getType() : nullptr),
245       Global(Global) {}
246 
247 uint32_t EventSymbol::getEventIndex() const {
248   if (auto *F = dyn_cast<DefinedEvent>(this))
249     return F->Event->getEventIndex();
250   assert(EventIndex != INVALID_INDEX);
251   return EventIndex;
252 }
253 
254 void EventSymbol::setEventIndex(uint32_t Index) {
255   LLVM_DEBUG(dbgs() << "setEventIndex " << Name << " -> " << Index << "\n");
256   assert(EventIndex == INVALID_INDEX);
257   EventIndex = Index;
258 }
259 
260 bool EventSymbol::hasEventIndex() const {
261   if (auto *F = dyn_cast<DefinedEvent>(this))
262     return F->Event->hasEventIndex();
263   return EventIndex != INVALID_INDEX;
264 }
265 
266 DefinedEvent::DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
267                            InputEvent *Event)
268     : EventSymbol(Name, DefinedEventKind, Flags, File,
269                   Event ? &Event->getType() : nullptr,
270                   Event ? &Event->Signature : nullptr),
271       Event(Event) {}
272 
273 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
274   assert(Section->OutputSec && Section->OutputSec->SectionSym);
275   return Section->OutputSec->SectionSym;
276 }
277 
278 void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
279 
280 std::string lld::toString(const wasm::Symbol &Sym) {
281   return lld::maybeDemangleSymbol(Sym.getName());
282 }
283 
284 std::string lld::maybeDemangleSymbol(StringRef Name) {
285   if (Config->Demangle)
286     if (Optional<std::string> S = demangleItanium(Name))
287       return *S;
288   return Name;
289 }
290 
291 std::string lld::toString(wasm::Symbol::Kind Kind) {
292   switch (Kind) {
293   case wasm::Symbol::DefinedFunctionKind:
294     return "DefinedFunction";
295   case wasm::Symbol::DefinedDataKind:
296     return "DefinedData";
297   case wasm::Symbol::DefinedGlobalKind:
298     return "DefinedGlobal";
299   case wasm::Symbol::DefinedEventKind:
300     return "DefinedEvent";
301   case wasm::Symbol::UndefinedFunctionKind:
302     return "UndefinedFunction";
303   case wasm::Symbol::UndefinedDataKind:
304     return "UndefinedData";
305   case wasm::Symbol::UndefinedGlobalKind:
306     return "UndefinedGlobal";
307   case wasm::Symbol::LazyKind:
308     return "LazyKind";
309   case wasm::Symbol::SectionKind:
310     return "SectionKind";
311   case wasm::Symbol::OutputSectionKind:
312     return "OutputSectionKind";
313   }
314   llvm_unreachable("invalid symbol kind");
315 }
316 
317 
318 void lld::wasm::printTraceSymbolUndefined(StringRef Name, const InputFile* File) {
319   message(toString(File) + ": reference to " + Name);
320 }
321 
322 // Print out a log message for --trace-symbol.
323 void lld::wasm::printTraceSymbol(Symbol *Sym) {
324   // Undefined symbols are traced via printTraceSymbolUndefined
325   if (Sym->isUndefined())
326     return;
327 
328   std::string S;
329   if (Sym->isLazy())
330     S = ": lazy definition of ";
331   else
332     S = ": definition of ";
333 
334   message(toString(Sym->getFile()) + S + Sym->getName());
335 }
336 
337 const char *lld::wasm::DefaultModule = "env";
338 const char *lld::wasm::FunctionTableName = "__indirect_function_table";
339