xref: /openbsd-src/gnu/llvm/lld/wasm/Symbols.cpp (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
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::object;
24 using namespace llvm::wasm;
25 
26 namespace lld {
27 std::string toString(const wasm::Symbol &sym) {
28   return maybeDemangleSymbol(sym.getName());
29 }
30 
31 std::string maybeDemangleSymbol(StringRef name) {
32   // WebAssembly requires caller and callee signatures to match, so we mangle
33   // `main` in the case where we need to pass it arguments.
34   if (name == "__main_argc_argv")
35     return "main";
36   if (wasm::config->demangle)
37     return demangleItanium(name);
38   return std::string(name);
39 }
40 
41 std::string toString(wasm::Symbol::Kind kind) {
42   switch (kind) {
43   case wasm::Symbol::DefinedFunctionKind:
44     return "DefinedFunction";
45   case wasm::Symbol::DefinedDataKind:
46     return "DefinedData";
47   case wasm::Symbol::DefinedGlobalKind:
48     return "DefinedGlobal";
49   case wasm::Symbol::DefinedEventKind:
50     return "DefinedEvent";
51   case wasm::Symbol::UndefinedFunctionKind:
52     return "UndefinedFunction";
53   case wasm::Symbol::UndefinedDataKind:
54     return "UndefinedData";
55   case wasm::Symbol::UndefinedGlobalKind:
56     return "UndefinedGlobal";
57   case wasm::Symbol::LazyKind:
58     return "LazyKind";
59   case wasm::Symbol::SectionKind:
60     return "SectionKind";
61   case wasm::Symbol::OutputSectionKind:
62     return "OutputSectionKind";
63   }
64   llvm_unreachable("invalid symbol kind");
65 }
66 
67 namespace wasm {
68 DefinedFunction *WasmSym::callCtors;
69 DefinedFunction *WasmSym::initMemory;
70 DefinedFunction *WasmSym::applyRelocs;
71 DefinedFunction *WasmSym::initTLS;
72 DefinedData *WasmSym::dsoHandle;
73 DefinedData *WasmSym::dataEnd;
74 DefinedData *WasmSym::globalBase;
75 DefinedData *WasmSym::heapBase;
76 DefinedData *WasmSym::initMemoryFlag;
77 GlobalSymbol *WasmSym::stackPointer;
78 GlobalSymbol *WasmSym::tlsBase;
79 GlobalSymbol *WasmSym::tlsSize;
80 GlobalSymbol *WasmSym::tlsAlign;
81 UndefinedGlobal *WasmSym::tableBase;
82 DefinedData *WasmSym::definedTableBase;
83 UndefinedGlobal *WasmSym::memoryBase;
84 DefinedData *WasmSym::definedMemoryBase;
85 
86 WasmSymbolType Symbol::getWasmType() const {
87   if (isa<FunctionSymbol>(this))
88     return WASM_SYMBOL_TYPE_FUNCTION;
89   if (isa<DataSymbol>(this))
90     return WASM_SYMBOL_TYPE_DATA;
91   if (isa<GlobalSymbol>(this))
92     return WASM_SYMBOL_TYPE_GLOBAL;
93   if (isa<EventSymbol>(this))
94     return WASM_SYMBOL_TYPE_EVENT;
95   if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))
96     return WASM_SYMBOL_TYPE_SECTION;
97   llvm_unreachable("invalid symbol kind");
98 }
99 
100 const WasmSignature *Symbol::getSignature() const {
101   if (auto* f = dyn_cast<FunctionSymbol>(this))
102     return f->signature;
103   if (auto *l = dyn_cast<LazySymbol>(this))
104     return l->signature;
105   return nullptr;
106 }
107 
108 InputChunk *Symbol::getChunk() const {
109   if (auto *f = dyn_cast<DefinedFunction>(this))
110     return f->function;
111   if (auto *d = dyn_cast<DefinedData>(this))
112     return d->segment;
113   return nullptr;
114 }
115 
116 bool Symbol::isDiscarded() const {
117   if (InputChunk *c = getChunk())
118     return c->discarded;
119   return false;
120 }
121 
122 bool Symbol::isLive() const {
123   if (auto *g = dyn_cast<DefinedGlobal>(this))
124     return g->global->live;
125   if (auto *e = dyn_cast<DefinedEvent>(this))
126     return e->event->live;
127   if (InputChunk *c = getChunk())
128     return c->live;
129   return referenced;
130 }
131 
132 void Symbol::markLive() {
133   assert(!isDiscarded());
134   if (auto *g = dyn_cast<DefinedGlobal>(this))
135     g->global->live = true;
136   if (auto *e = dyn_cast<DefinedEvent>(this))
137     e->event->live = true;
138   if (InputChunk *c = getChunk())
139     c->live = true;
140   referenced = true;
141 }
142 
143 uint32_t Symbol::getOutputSymbolIndex() const {
144   assert(outputSymbolIndex != INVALID_INDEX);
145   return outputSymbolIndex;
146 }
147 
148 void Symbol::setOutputSymbolIndex(uint32_t index) {
149   LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index
150                     << "\n");
151   assert(outputSymbolIndex == INVALID_INDEX);
152   outputSymbolIndex = index;
153 }
154 
155 void Symbol::setGOTIndex(uint32_t index) {
156   LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");
157   assert(gotIndex == INVALID_INDEX);
158   if (config->isPic) {
159     // Any symbol that is assigned a GOT entry must be exported otherwise the
160     // dynamic linker won't be able create the entry that contains it.
161     forceExport = true;
162   }
163   gotIndex = index;
164 }
165 
166 bool Symbol::isWeak() const {
167   return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
168 }
169 
170 bool Symbol::isLocal() const {
171   return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
172 }
173 
174 bool Symbol::isHidden() const {
175   return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
176 }
177 
178 void Symbol::setHidden(bool isHidden) {
179   LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
180   flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
181   if (isHidden)
182     flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
183   else
184     flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
185 }
186 
187 bool Symbol::isExported() const {
188   if (!isDefined() || isLocal())
189     return false;
190 
191   if (forceExport || config->exportAll)
192     return true;
193 
194   if (config->exportDynamic && !isHidden())
195     return true;
196 
197   return flags & WASM_SYMBOL_EXPORTED;
198 }
199 
200 bool Symbol::isNoStrip() const {
201   return flags & WASM_SYMBOL_NO_STRIP;
202 }
203 
204 uint32_t FunctionSymbol::getFunctionIndex() const {
205   if (auto *f = dyn_cast<DefinedFunction>(this))
206     return f->function->getFunctionIndex();
207   assert(functionIndex != INVALID_INDEX);
208   return functionIndex;
209 }
210 
211 void FunctionSymbol::setFunctionIndex(uint32_t index) {
212   LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");
213   assert(functionIndex == INVALID_INDEX);
214   functionIndex = index;
215 }
216 
217 bool FunctionSymbol::hasFunctionIndex() const {
218   if (auto *f = dyn_cast<DefinedFunction>(this))
219     return f->function->hasFunctionIndex();
220   return functionIndex != INVALID_INDEX;
221 }
222 
223 uint32_t FunctionSymbol::getTableIndex() const {
224   if (auto *f = dyn_cast<DefinedFunction>(this))
225     return f->function->getTableIndex();
226   assert(tableIndex != INVALID_INDEX);
227   return tableIndex;
228 }
229 
230 bool FunctionSymbol::hasTableIndex() const {
231   if (auto *f = dyn_cast<DefinedFunction>(this))
232     return f->function->hasTableIndex();
233   return tableIndex != INVALID_INDEX;
234 }
235 
236 void FunctionSymbol::setTableIndex(uint32_t index) {
237   // For imports, we set the table index here on the Symbol; for defined
238   // functions we set the index on the InputFunction so that we don't export
239   // the same thing twice (keeps the table size down).
240   if (auto *f = dyn_cast<DefinedFunction>(this)) {
241     f->function->setTableIndex(index);
242     return;
243   }
244   LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");
245   assert(tableIndex == INVALID_INDEX);
246   tableIndex = index;
247 }
248 
249 DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
250                                  InputFunction *function)
251     : FunctionSymbol(name, DefinedFunctionKind, flags, f,
252                      function ? &function->signature : nullptr),
253       function(function) {}
254 
255 uint64_t DefinedData::getVirtualAddress() const {
256   LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
257   if (segment) {
258     // For thread local data, the symbol location is relative to the start of
259     // the .tdata section, since they are used as offsets from __tls_base.
260     // Hence, we do not add in segment->outputSeg->startVA.
261     if (segment->outputSeg->name == ".tdata")
262       return segment->outputSegmentOffset + offset;
263     return segment->outputSeg->startVA + segment->outputSegmentOffset + offset;
264   }
265   return offset;
266 }
267 
268 void DefinedData::setVirtualAddress(uint64_t value) {
269   LLVM_DEBUG(dbgs() << "setVirtualAddress " << name << " -> " << value << "\n");
270   assert(!segment);
271   offset = value;
272 }
273 
274 uint64_t DefinedData::getOutputSegmentOffset() const {
275   LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
276   return segment->outputSegmentOffset + offset;
277 }
278 
279 uint64_t DefinedData::getOutputSegmentIndex() const {
280   LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
281   return segment->outputSeg->index;
282 }
283 
284 uint32_t GlobalSymbol::getGlobalIndex() const {
285   if (auto *f = dyn_cast<DefinedGlobal>(this))
286     return f->global->getGlobalIndex();
287   assert(globalIndex != INVALID_INDEX);
288   return globalIndex;
289 }
290 
291 void GlobalSymbol::setGlobalIndex(uint32_t index) {
292   LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");
293   assert(globalIndex == INVALID_INDEX);
294   globalIndex = index;
295 }
296 
297 bool GlobalSymbol::hasGlobalIndex() const {
298   if (auto *f = dyn_cast<DefinedGlobal>(this))
299     return f->global->hasGlobalIndex();
300   return globalIndex != INVALID_INDEX;
301 }
302 
303 DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
304                              InputGlobal *global)
305     : GlobalSymbol(name, DefinedGlobalKind, flags, file,
306                    global ? &global->getType() : nullptr),
307       global(global) {}
308 
309 uint32_t EventSymbol::getEventIndex() const {
310   if (auto *f = dyn_cast<DefinedEvent>(this))
311     return f->event->getEventIndex();
312   assert(eventIndex != INVALID_INDEX);
313   return eventIndex;
314 }
315 
316 void EventSymbol::setEventIndex(uint32_t index) {
317   LLVM_DEBUG(dbgs() << "setEventIndex " << name << " -> " << index << "\n");
318   assert(eventIndex == INVALID_INDEX);
319   eventIndex = index;
320 }
321 
322 bool EventSymbol::hasEventIndex() const {
323   if (auto *f = dyn_cast<DefinedEvent>(this))
324     return f->event->hasEventIndex();
325   return eventIndex != INVALID_INDEX;
326 }
327 
328 DefinedEvent::DefinedEvent(StringRef name, uint32_t flags, InputFile *file,
329                            InputEvent *event)
330     : EventSymbol(name, DefinedEventKind, flags, file,
331                   event ? &event->getType() : nullptr,
332                   event ? &event->signature : nullptr),
333       event(event) {}
334 
335 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
336   assert(section->outputSec && section->outputSec->sectionSym);
337   return section->outputSec->sectionSym;
338 }
339 
340 void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); }
341 
342 MemoryBufferRef LazySymbol::getMemberBuffer() {
343   Archive::Child c =
344       CHECK(archiveSymbol.getMember(),
345             "could not get the member for symbol " + toString(*this));
346 
347   return CHECK(c.getMemoryBufferRef(),
348                "could not get the buffer for the member defining symbol " +
349                    toString(*this));
350 }
351 
352 void printTraceSymbolUndefined(StringRef name, const InputFile* file) {
353   message(toString(file) + ": reference to " + name);
354 }
355 
356 // Print out a log message for --trace-symbol.
357 void printTraceSymbol(Symbol *sym) {
358   // Undefined symbols are traced via printTraceSymbolUndefined
359   if (sym->isUndefined())
360     return;
361 
362   std::string s;
363   if (sym->isLazy())
364     s = ": lazy definition of ";
365   else
366     s = ": definition of ";
367 
368   message(toString(sym->getFile()) + s + sym->getName());
369 }
370 
371 const char *defaultModule = "env";
372 const char *functionTableName = "__indirect_function_table";
373 
374 } // namespace wasm
375 } // namespace lld
376