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