1 //===- Symbols.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
11 #include "InputChunks.h"
12 #include "InputElement.h"
13 #include "InputFiles.h"
14 #include "OutputSections.h"
15 #include "OutputSegment.h"
16 #include "lld/Common/ErrorHandler.h"
17 #include "lld/Common/Memory.h"
18 #include "llvm/Demangle/Demangle.h"
20 #define DEBUG_TYPE "lld"
23 using namespace llvm::object
;
24 using namespace llvm::wasm
;
25 using namespace lld::wasm
;
28 std::string
toString(const wasm::Symbol
&sym
) {
29 return maybeDemangleSymbol(sym
.getName());
32 std::string
maybeDemangleSymbol(StringRef name
) {
33 // WebAssembly requires caller and callee signatures to match, so we mangle
34 // `main` in the case where we need to pass it arguments.
35 if (name
== "__main_argc_argv")
37 if (wasm::config
->demangle
)
38 return demangle(name
);
42 std::string
toString(wasm::Symbol::Kind kind
) {
44 case wasm::Symbol::DefinedFunctionKind
:
45 return "DefinedFunction";
46 case wasm::Symbol::DefinedDataKind
:
48 case wasm::Symbol::DefinedGlobalKind
:
49 return "DefinedGlobal";
50 case wasm::Symbol::DefinedTableKind
:
51 return "DefinedTable";
52 case wasm::Symbol::DefinedTagKind
:
54 case wasm::Symbol::UndefinedFunctionKind
:
55 return "UndefinedFunction";
56 case wasm::Symbol::UndefinedDataKind
:
57 return "UndefinedData";
58 case wasm::Symbol::UndefinedGlobalKind
:
59 return "UndefinedGlobal";
60 case wasm::Symbol::UndefinedTableKind
:
61 return "UndefinedTable";
62 case wasm::Symbol::UndefinedTagKind
:
63 return "UndefinedTag";
64 case wasm::Symbol::LazyKind
:
66 case wasm::Symbol::SectionKind
:
68 case wasm::Symbol::OutputSectionKind
:
69 return "OutputSectionKind";
71 llvm_unreachable("invalid symbol kind");
75 DefinedFunction
*WasmSym::callCtors
;
76 DefinedFunction
*WasmSym::callDtors
;
77 DefinedFunction
*WasmSym::initMemory
;
78 DefinedFunction
*WasmSym::applyDataRelocs
;
79 DefinedFunction
*WasmSym::applyGlobalRelocs
;
80 DefinedFunction
*WasmSym::applyTLSRelocs
;
81 DefinedFunction
*WasmSym::applyGlobalTLSRelocs
;
82 DefinedFunction
*WasmSym::initTLS
;
83 DefinedFunction
*WasmSym::startFunction
;
84 DefinedData
*WasmSym::dsoHandle
;
85 DefinedData
*WasmSym::dataEnd
;
86 DefinedData
*WasmSym::globalBase
;
87 DefinedData
*WasmSym::heapBase
;
88 DefinedData
*WasmSym::heapEnd
;
89 DefinedData
*WasmSym::initMemoryFlag
;
90 GlobalSymbol
*WasmSym::stackPointer
;
91 DefinedData
*WasmSym::stackLow
;
92 DefinedData
*WasmSym::stackHigh
;
93 GlobalSymbol
*WasmSym::tlsBase
;
94 GlobalSymbol
*WasmSym::tlsSize
;
95 GlobalSymbol
*WasmSym::tlsAlign
;
96 UndefinedGlobal
*WasmSym::tableBase
;
97 DefinedData
*WasmSym::definedTableBase
;
98 UndefinedGlobal
*WasmSym::tableBase32
;
99 DefinedData
*WasmSym::definedTableBase32
;
100 UndefinedGlobal
*WasmSym::memoryBase
;
101 DefinedData
*WasmSym::definedMemoryBase
;
102 TableSymbol
*WasmSym::indirectFunctionTable
;
104 WasmSymbolType
Symbol::getWasmType() const {
105 if (isa
<FunctionSymbol
>(this))
106 return WASM_SYMBOL_TYPE_FUNCTION
;
107 if (isa
<DataSymbol
>(this))
108 return WASM_SYMBOL_TYPE_DATA
;
109 if (isa
<GlobalSymbol
>(this))
110 return WASM_SYMBOL_TYPE_GLOBAL
;
111 if (isa
<TagSymbol
>(this))
112 return WASM_SYMBOL_TYPE_TAG
;
113 if (isa
<TableSymbol
>(this))
114 return WASM_SYMBOL_TYPE_TABLE
;
115 if (isa
<SectionSymbol
>(this) || isa
<OutputSectionSymbol
>(this))
116 return WASM_SYMBOL_TYPE_SECTION
;
117 llvm_unreachable("invalid symbol kind");
120 const WasmSignature
*Symbol::getSignature() const {
121 if (auto* f
= dyn_cast
<FunctionSymbol
>(this))
123 if (auto *t
= dyn_cast
<TagSymbol
>(this))
125 if (auto *l
= dyn_cast
<LazySymbol
>(this))
130 InputChunk
*Symbol::getChunk() const {
131 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
133 if (auto *f
= dyn_cast
<UndefinedFunction
>(this))
135 return f
->stubFunction
->function
;
136 if (auto *d
= dyn_cast
<DefinedData
>(this))
141 bool Symbol::isDiscarded() const {
142 if (InputChunk
*c
= getChunk())
147 bool Symbol::isLive() const {
148 if (auto *g
= dyn_cast
<DefinedGlobal
>(this))
149 return g
->global
->live
;
150 if (auto *t
= dyn_cast
<DefinedTag
>(this))
152 if (auto *t
= dyn_cast
<DefinedTable
>(this))
153 return t
->table
->live
;
154 if (InputChunk
*c
= getChunk())
159 void Symbol::markLive() {
160 assert(!isDiscarded());
162 if (file
!= nullptr && isDefined())
164 if (auto *g
= dyn_cast
<DefinedGlobal
>(this))
165 g
->global
->live
= true;
166 if (auto *t
= dyn_cast
<DefinedTag
>(this))
168 if (auto *t
= dyn_cast
<DefinedTable
>(this))
169 t
->table
->live
= true;
170 if (InputChunk
*c
= getChunk()) {
171 // Usually, a whole chunk is marked as live or dead, but in mergeable
172 // (splittable) sections, each piece of data has independent liveness bit.
173 // So we explicitly tell it which offset is in use.
174 if (auto *d
= dyn_cast
<DefinedData
>(this)) {
175 if (auto *ms
= dyn_cast
<MergeInputChunk
>(c
)) {
176 ms
->getSectionPiece(d
->value
)->live
= true;
183 uint32_t Symbol::getOutputSymbolIndex() const {
184 assert(outputSymbolIndex
!= INVALID_INDEX
);
185 return outputSymbolIndex
;
188 void Symbol::setOutputSymbolIndex(uint32_t index
) {
189 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name
<< " -> " << index
191 assert(outputSymbolIndex
== INVALID_INDEX
);
192 outputSymbolIndex
= index
;
195 void Symbol::setGOTIndex(uint32_t index
) {
196 LLVM_DEBUG(dbgs() << "setGOTIndex " << name
<< " -> " << index
<< "\n");
197 assert(gotIndex
== INVALID_INDEX
);
201 bool Symbol::isWeak() const {
202 return (flags
& WASM_SYMBOL_BINDING_MASK
) == WASM_SYMBOL_BINDING_WEAK
;
205 bool Symbol::isLocal() const {
206 return (flags
& WASM_SYMBOL_BINDING_MASK
) == WASM_SYMBOL_BINDING_LOCAL
;
209 bool Symbol::isHidden() const {
210 return (flags
& WASM_SYMBOL_VISIBILITY_MASK
) == WASM_SYMBOL_VISIBILITY_HIDDEN
;
213 bool Symbol::isTLS() const { return flags
& WASM_SYMBOL_TLS
; }
215 void Symbol::setHidden(bool isHidden
) {
216 LLVM_DEBUG(dbgs() << "setHidden: " << name
<< " -> " << isHidden
<< "\n");
217 flags
&= ~WASM_SYMBOL_VISIBILITY_MASK
;
219 flags
|= WASM_SYMBOL_VISIBILITY_HIDDEN
;
221 flags
|= WASM_SYMBOL_VISIBILITY_DEFAULT
;
224 bool Symbol::isImported() const {
225 return isUndefined() && (importName
.has_value() || forceImport
);
228 bool Symbol::isExported() const {
229 if (!isDefined() || isLocal())
232 // Shared libraries must export all weakly defined symbols
233 // in case they contain the version that will be chosen by
234 // the dynamic linker.
235 if (config
->shared
&& isLive() && isWeak() && !isHidden())
238 if (config
->exportAll
|| (config
->exportDynamic
&& !isHidden()))
241 return isExportedExplicit();
244 bool Symbol::isExportedExplicit() const {
245 return forceExport
|| flags
& WASM_SYMBOL_EXPORTED
;
248 bool Symbol::isNoStrip() const {
249 return flags
& WASM_SYMBOL_NO_STRIP
;
252 uint32_t FunctionSymbol::getFunctionIndex() const {
253 if (const auto *u
= dyn_cast
<UndefinedFunction
>(this))
255 return u
->stubFunction
->getFunctionIndex();
256 if (functionIndex
!= INVALID_INDEX
)
257 return functionIndex
;
258 auto *f
= cast
<DefinedFunction
>(this);
259 return f
->function
->getFunctionIndex();
262 void FunctionSymbol::setFunctionIndex(uint32_t index
) {
263 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name
<< " -> " << index
<< "\n");
264 assert(functionIndex
== INVALID_INDEX
);
265 functionIndex
= index
;
268 bool FunctionSymbol::hasFunctionIndex() const {
269 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
270 return f
->function
->hasFunctionIndex();
271 return functionIndex
!= INVALID_INDEX
;
274 uint32_t FunctionSymbol::getTableIndex() const {
275 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
276 return f
->function
->getTableIndex();
277 assert(tableIndex
!= INVALID_INDEX
);
281 bool FunctionSymbol::hasTableIndex() const {
282 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
283 return f
->function
->hasTableIndex();
284 return tableIndex
!= INVALID_INDEX
;
287 void FunctionSymbol::setTableIndex(uint32_t index
) {
288 // For imports, we set the table index here on the Symbol; for defined
289 // functions we set the index on the InputFunction so that we don't export
290 // the same thing twice (keeps the table size down).
291 if (auto *f
= dyn_cast
<DefinedFunction
>(this)) {
292 f
->function
->setTableIndex(index
);
295 LLVM_DEBUG(dbgs() << "setTableIndex " << name
<< " -> " << index
<< "\n");
296 assert(tableIndex
== INVALID_INDEX
);
300 DefinedFunction::DefinedFunction(StringRef name
, uint32_t flags
, InputFile
*f
,
301 InputFunction
*function
)
302 : FunctionSymbol(name
, DefinedFunctionKind
, flags
, f
,
303 function
? &function
->signature
: nullptr),
304 function(function
) {}
306 uint32_t DefinedFunction::getExportedFunctionIndex() const {
307 return function
->getFunctionIndex();
310 uint64_t DefinedData::getVA() const {
311 LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
312 // In the shared memory case, TLS symbols are relative to the start of the TLS
313 // output segment (__tls_base). When building without shared memory, TLS
314 // symbols absolute, just like non-TLS.
315 if (isTLS() && config
->sharedMemory
)
316 return getOutputSegmentOffset();
318 return segment
->getVA(value
);
322 void DefinedData::setVA(uint64_t value_
) {
323 LLVM_DEBUG(dbgs() << "setVA " << name
<< " -> " << value_
<< "\n");
328 uint64_t DefinedData::getOutputSegmentOffset() const {
329 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
330 return segment
->getChunkOffset(value
);
333 uint64_t DefinedData::getOutputSegmentIndex() const {
334 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
335 return segment
->outputSeg
->index
;
338 uint32_t GlobalSymbol::getGlobalIndex() const {
339 if (auto *f
= dyn_cast
<DefinedGlobal
>(this))
340 return f
->global
->getAssignedIndex();
341 assert(globalIndex
!= INVALID_INDEX
);
345 void GlobalSymbol::setGlobalIndex(uint32_t index
) {
346 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name
<< " -> " << index
<< "\n");
347 assert(globalIndex
== INVALID_INDEX
);
351 bool GlobalSymbol::hasGlobalIndex() const {
352 if (auto *f
= dyn_cast
<DefinedGlobal
>(this))
353 return f
->global
->hasAssignedIndex();
354 return globalIndex
!= INVALID_INDEX
;
357 DefinedGlobal::DefinedGlobal(StringRef name
, uint32_t flags
, InputFile
*file
,
359 : GlobalSymbol(name
, DefinedGlobalKind
, flags
, file
,
360 global
? &global
->getType() : nullptr),
363 uint32_t TagSymbol::getTagIndex() const {
364 if (auto *f
= dyn_cast
<DefinedTag
>(this))
365 return f
->tag
->getAssignedIndex();
366 assert(tagIndex
!= INVALID_INDEX
);
370 void TagSymbol::setTagIndex(uint32_t index
) {
371 LLVM_DEBUG(dbgs() << "setTagIndex " << name
<< " -> " << index
<< "\n");
372 assert(tagIndex
== INVALID_INDEX
);
376 bool TagSymbol::hasTagIndex() const {
377 if (auto *f
= dyn_cast
<DefinedTag
>(this))
378 return f
->tag
->hasAssignedIndex();
379 return tagIndex
!= INVALID_INDEX
;
382 DefinedTag::DefinedTag(StringRef name
, uint32_t flags
, InputFile
*file
,
384 : TagSymbol(name
, DefinedTagKind
, flags
, file
,
385 tag
? &tag
->signature
: nullptr),
388 void TableSymbol::setLimits(const WasmLimits
&limits
) {
389 if (auto *t
= dyn_cast
<DefinedTable
>(this))
390 t
->table
->setLimits(limits
);
391 auto *newType
= make
<WasmTableType
>(*tableType
);
392 newType
->Limits
= limits
;
396 uint32_t TableSymbol::getTableNumber() const {
397 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
398 return t
->table
->getAssignedIndex();
399 assert(tableNumber
!= INVALID_INDEX
);
403 void TableSymbol::setTableNumber(uint32_t number
) {
404 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
405 return t
->table
->assignIndex(number
);
406 LLVM_DEBUG(dbgs() << "setTableNumber " << name
<< " -> " << number
<< "\n");
407 assert(tableNumber
== INVALID_INDEX
);
408 tableNumber
= number
;
411 bool TableSymbol::hasTableNumber() const {
412 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
413 return t
->table
->hasAssignedIndex();
414 return tableNumber
!= INVALID_INDEX
;
417 DefinedTable::DefinedTable(StringRef name
, uint32_t flags
, InputFile
*file
,
419 : TableSymbol(name
, DefinedTableKind
, flags
, file
,
420 table
? &table
->getType() : nullptr),
423 const OutputSectionSymbol
*SectionSymbol::getOutputSectionSymbol() const {
424 assert(section
->outputSec
&& section
->outputSec
->sectionSym
);
425 return section
->outputSec
->sectionSym
;
428 void LazySymbol::fetch() { cast
<ArchiveFile
>(file
)->addMember(&archiveSymbol
); }
430 void LazySymbol::setWeak() {
431 flags
|= (flags
& ~WASM_SYMBOL_BINDING_MASK
) | WASM_SYMBOL_BINDING_WEAK
;
434 MemoryBufferRef
LazySymbol::getMemberBuffer() {
436 CHECK(archiveSymbol
.getMember(),
437 "could not get the member for symbol " + toString(*this));
439 return CHECK(c
.getMemoryBufferRef(),
440 "could not get the buffer for the member defining symbol " +
444 void printTraceSymbolUndefined(StringRef name
, const InputFile
* file
) {
445 message(toString(file
) + ": reference to " + name
);
448 // Print out a log message for --trace-symbol.
449 void printTraceSymbol(Symbol
*sym
) {
450 // Undefined symbols are traced via printTraceSymbolUndefined
451 if (sym
->isUndefined())
456 s
= ": lazy definition of ";
458 s
= ": definition of ";
460 message(toString(sym
->getFile()) + s
+ sym
->getName());
463 const char *defaultModule
= "env";
464 const char *functionTableName
= "__indirect_function_table";
465 const char *memoryName
= "memory";