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 "lld/Common/Strings.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")
38 return demangle(name
, config
->demangle
);
41 std::string
toString(wasm::Symbol::Kind kind
) {
43 case wasm::Symbol::DefinedFunctionKind
:
44 return "DefinedFunction";
45 case wasm::Symbol::DefinedDataKind
:
47 case wasm::Symbol::DefinedGlobalKind
:
48 return "DefinedGlobal";
49 case wasm::Symbol::DefinedTableKind
:
50 return "DefinedTable";
51 case wasm::Symbol::DefinedTagKind
:
53 case wasm::Symbol::UndefinedFunctionKind
:
54 return "UndefinedFunction";
55 case wasm::Symbol::UndefinedDataKind
:
56 return "UndefinedData";
57 case wasm::Symbol::UndefinedGlobalKind
:
58 return "UndefinedGlobal";
59 case wasm::Symbol::UndefinedTableKind
:
60 return "UndefinedTable";
61 case wasm::Symbol::UndefinedTagKind
:
62 return "UndefinedTag";
63 case wasm::Symbol::LazyKind
:
65 case wasm::Symbol::SectionKind
:
67 case wasm::Symbol::OutputSectionKind
:
68 return "OutputSectionKind";
70 llvm_unreachable("invalid symbol kind");
74 DefinedFunction
*WasmSym::callCtors
;
75 DefinedFunction
*WasmSym::callDtors
;
76 DefinedFunction
*WasmSym::initMemory
;
77 DefinedFunction
*WasmSym::applyDataRelocs
;
78 DefinedFunction
*WasmSym::applyGlobalRelocs
;
79 DefinedFunction
*WasmSym::applyGlobalTLSRelocs
;
80 DefinedFunction
*WasmSym::initTLS
;
81 DefinedFunction
*WasmSym::startFunction
;
82 DefinedData
*WasmSym::dsoHandle
;
83 DefinedData
*WasmSym::dataEnd
;
84 DefinedData
*WasmSym::globalBase
;
85 DefinedData
*WasmSym::heapBase
;
86 DefinedData
*WasmSym::initMemoryFlag
;
87 GlobalSymbol
*WasmSym::stackPointer
;
88 GlobalSymbol
*WasmSym::tlsBase
;
89 GlobalSymbol
*WasmSym::tlsSize
;
90 GlobalSymbol
*WasmSym::tlsAlign
;
91 UndefinedGlobal
*WasmSym::tableBase
;
92 DefinedData
*WasmSym::definedTableBase
;
93 UndefinedGlobal
*WasmSym::tableBase32
;
94 DefinedData
*WasmSym::definedTableBase32
;
95 UndefinedGlobal
*WasmSym::memoryBase
;
96 DefinedData
*WasmSym::definedMemoryBase
;
97 TableSymbol
*WasmSym::indirectFunctionTable
;
99 WasmSymbolType
Symbol::getWasmType() const {
100 if (isa
<FunctionSymbol
>(this))
101 return WASM_SYMBOL_TYPE_FUNCTION
;
102 if (isa
<DataSymbol
>(this))
103 return WASM_SYMBOL_TYPE_DATA
;
104 if (isa
<GlobalSymbol
>(this))
105 return WASM_SYMBOL_TYPE_GLOBAL
;
106 if (isa
<TagSymbol
>(this))
107 return WASM_SYMBOL_TYPE_TAG
;
108 if (isa
<TableSymbol
>(this))
109 return WASM_SYMBOL_TYPE_TABLE
;
110 if (isa
<SectionSymbol
>(this) || isa
<OutputSectionSymbol
>(this))
111 return WASM_SYMBOL_TYPE_SECTION
;
112 llvm_unreachable("invalid symbol kind");
115 const WasmSignature
*Symbol::getSignature() const {
116 if (auto* f
= dyn_cast
<FunctionSymbol
>(this))
118 if (auto *t
= dyn_cast
<TagSymbol
>(this))
120 if (auto *l
= dyn_cast
<LazySymbol
>(this))
125 InputChunk
*Symbol::getChunk() const {
126 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
128 if (auto *f
= dyn_cast
<UndefinedFunction
>(this))
130 return f
->stubFunction
->function
;
131 if (auto *d
= dyn_cast
<DefinedData
>(this))
136 bool Symbol::isDiscarded() const {
137 if (InputChunk
*c
= getChunk())
142 bool Symbol::isLive() const {
143 if (auto *g
= dyn_cast
<DefinedGlobal
>(this))
144 return g
->global
->live
;
145 if (auto *t
= dyn_cast
<DefinedTag
>(this))
147 if (auto *t
= dyn_cast
<DefinedTable
>(this))
148 return t
->table
->live
;
149 if (InputChunk
*c
= getChunk())
154 void Symbol::markLive() {
155 assert(!isDiscarded());
157 if (file
!= nullptr && isDefined())
159 if (auto *g
= dyn_cast
<DefinedGlobal
>(this))
160 g
->global
->live
= true;
161 if (auto *t
= dyn_cast
<DefinedTag
>(this))
163 if (auto *t
= dyn_cast
<DefinedTable
>(this))
164 t
->table
->live
= true;
165 if (InputChunk
*c
= getChunk()) {
166 // Usually, a whole chunk is marked as live or dead, but in mergeable
167 // (splittable) sections, each piece of data has independent liveness bit.
168 // So we explicitly tell it which offset is in use.
169 if (auto *d
= dyn_cast
<DefinedData
>(this)) {
170 if (auto *ms
= dyn_cast
<MergeInputChunk
>(c
)) {
171 ms
->getSectionPiece(d
->value
)->live
= true;
178 uint32_t Symbol::getOutputSymbolIndex() const {
179 assert(outputSymbolIndex
!= INVALID_INDEX
);
180 return outputSymbolIndex
;
183 void Symbol::setOutputSymbolIndex(uint32_t index
) {
184 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name
<< " -> " << index
186 assert(outputSymbolIndex
== INVALID_INDEX
);
187 outputSymbolIndex
= index
;
190 void Symbol::setGOTIndex(uint32_t index
) {
191 LLVM_DEBUG(dbgs() << "setGOTIndex " << name
<< " -> " << index
<< "\n");
192 assert(gotIndex
== INVALID_INDEX
);
196 bool Symbol::isWeak() const {
197 return (flags
& WASM_SYMBOL_BINDING_MASK
) == WASM_SYMBOL_BINDING_WEAK
;
200 bool Symbol::isLocal() const {
201 return (flags
& WASM_SYMBOL_BINDING_MASK
) == WASM_SYMBOL_BINDING_LOCAL
;
204 bool Symbol::isHidden() const {
205 return (flags
& WASM_SYMBOL_VISIBILITY_MASK
) == WASM_SYMBOL_VISIBILITY_HIDDEN
;
208 bool Symbol::isTLS() const { return flags
& WASM_SYMBOL_TLS
; }
210 void Symbol::setHidden(bool isHidden
) {
211 LLVM_DEBUG(dbgs() << "setHidden: " << name
<< " -> " << isHidden
<< "\n");
212 flags
&= ~WASM_SYMBOL_VISIBILITY_MASK
;
214 flags
|= WASM_SYMBOL_VISIBILITY_HIDDEN
;
216 flags
|= WASM_SYMBOL_VISIBILITY_DEFAULT
;
219 bool Symbol::isExported() const {
220 // Shared libraries must export all weakly defined symbols
221 // in case they contain the version that will be chosen by
222 // the dynamic linker.
223 if (config
->shared
&& isLive() && isDefined() && isWeak())
226 if (!isDefined() || isLocal())
229 if (config
->exportAll
|| (config
->exportDynamic
&& !isHidden()))
232 return isExportedExplicit();
235 bool Symbol::isExportedExplicit() const {
236 return forceExport
|| flags
& WASM_SYMBOL_EXPORTED
;
239 bool Symbol::isNoStrip() const {
240 return flags
& WASM_SYMBOL_NO_STRIP
;
243 uint32_t FunctionSymbol::getFunctionIndex() const {
244 if (const auto *u
= dyn_cast
<UndefinedFunction
>(this))
246 return u
->stubFunction
->getFunctionIndex();
247 if (functionIndex
!= INVALID_INDEX
)
248 return functionIndex
;
249 auto *f
= cast
<DefinedFunction
>(this);
250 return f
->function
->getFunctionIndex();
253 void FunctionSymbol::setFunctionIndex(uint32_t index
) {
254 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name
<< " -> " << index
<< "\n");
255 assert(functionIndex
== INVALID_INDEX
);
256 functionIndex
= index
;
259 bool FunctionSymbol::hasFunctionIndex() const {
260 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
261 return f
->function
->hasFunctionIndex();
262 return functionIndex
!= INVALID_INDEX
;
265 uint32_t FunctionSymbol::getTableIndex() const {
266 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
267 return f
->function
->getTableIndex();
268 assert(tableIndex
!= INVALID_INDEX
);
272 bool FunctionSymbol::hasTableIndex() const {
273 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
274 return f
->function
->hasTableIndex();
275 return tableIndex
!= INVALID_INDEX
;
278 void FunctionSymbol::setTableIndex(uint32_t index
) {
279 // For imports, we set the table index here on the Symbol; for defined
280 // functions we set the index on the InputFunction so that we don't export
281 // the same thing twice (keeps the table size down).
282 if (auto *f
= dyn_cast
<DefinedFunction
>(this)) {
283 f
->function
->setTableIndex(index
);
286 LLVM_DEBUG(dbgs() << "setTableIndex " << name
<< " -> " << index
<< "\n");
287 assert(tableIndex
== INVALID_INDEX
);
291 DefinedFunction::DefinedFunction(StringRef name
, uint32_t flags
, InputFile
*f
,
292 InputFunction
*function
)
293 : FunctionSymbol(name
, DefinedFunctionKind
, flags
, f
,
294 function
? &function
->signature
: nullptr),
295 function(function
) {}
297 uint32_t DefinedFunction::getExportedFunctionIndex() const {
298 return function
->getFunctionIndex();
301 uint64_t DefinedData::getVA() const {
302 LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
303 // In the shared memory case, TLS symbols are relative to the start of the TLS
304 // output segment (__tls_base). When building without shared memory, TLS
305 // symbols absolute, just like non-TLS.
306 if (isTLS() && config
->sharedMemory
)
307 return getOutputSegmentOffset() + value
;
309 return segment
->getVA(value
);
313 void DefinedData::setVA(uint64_t value_
) {
314 LLVM_DEBUG(dbgs() << "setVA " << name
<< " -> " << value_
<< "\n");
319 uint64_t DefinedData::getOutputSegmentOffset() const {
320 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
321 return segment
->getChunkOffset(value
);
324 uint64_t DefinedData::getOutputSegmentIndex() const {
325 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
326 return segment
->outputSeg
->index
;
329 uint32_t GlobalSymbol::getGlobalIndex() const {
330 if (auto *f
= dyn_cast
<DefinedGlobal
>(this))
331 return f
->global
->getAssignedIndex();
332 assert(globalIndex
!= INVALID_INDEX
);
336 void GlobalSymbol::setGlobalIndex(uint32_t index
) {
337 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name
<< " -> " << index
<< "\n");
338 assert(globalIndex
== INVALID_INDEX
);
342 bool GlobalSymbol::hasGlobalIndex() const {
343 if (auto *f
= dyn_cast
<DefinedGlobal
>(this))
344 return f
->global
->hasAssignedIndex();
345 return globalIndex
!= INVALID_INDEX
;
348 DefinedGlobal::DefinedGlobal(StringRef name
, uint32_t flags
, InputFile
*file
,
350 : GlobalSymbol(name
, DefinedGlobalKind
, flags
, file
,
351 global
? &global
->getType() : nullptr),
354 uint32_t TagSymbol::getTagIndex() const {
355 if (auto *f
= dyn_cast
<DefinedTag
>(this))
356 return f
->tag
->getAssignedIndex();
357 assert(tagIndex
!= INVALID_INDEX
);
361 void TagSymbol::setTagIndex(uint32_t index
) {
362 LLVM_DEBUG(dbgs() << "setTagIndex " << name
<< " -> " << index
<< "\n");
363 assert(tagIndex
== INVALID_INDEX
);
367 bool TagSymbol::hasTagIndex() const {
368 if (auto *f
= dyn_cast
<DefinedTag
>(this))
369 return f
->tag
->hasAssignedIndex();
370 return tagIndex
!= INVALID_INDEX
;
373 DefinedTag::DefinedTag(StringRef name
, uint32_t flags
, InputFile
*file
,
375 : TagSymbol(name
, DefinedTagKind
, flags
, file
,
376 tag
? &tag
->signature
: nullptr),
379 void TableSymbol::setLimits(const WasmLimits
&limits
) {
380 if (auto *t
= dyn_cast
<DefinedTable
>(this))
381 t
->table
->setLimits(limits
);
382 auto *newType
= make
<WasmTableType
>(*tableType
);
383 newType
->Limits
= limits
;
387 uint32_t TableSymbol::getTableNumber() const {
388 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
389 return t
->table
->getAssignedIndex();
390 assert(tableNumber
!= INVALID_INDEX
);
394 void TableSymbol::setTableNumber(uint32_t number
) {
395 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
396 return t
->table
->assignIndex(number
);
397 LLVM_DEBUG(dbgs() << "setTableNumber " << name
<< " -> " << number
<< "\n");
398 assert(tableNumber
== INVALID_INDEX
);
399 tableNumber
= number
;
402 bool TableSymbol::hasTableNumber() const {
403 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
404 return t
->table
->hasAssignedIndex();
405 return tableNumber
!= INVALID_INDEX
;
408 DefinedTable::DefinedTable(StringRef name
, uint32_t flags
, InputFile
*file
,
410 : TableSymbol(name
, DefinedTableKind
, flags
, file
,
411 table
? &table
->getType() : nullptr),
414 const OutputSectionSymbol
*SectionSymbol::getOutputSectionSymbol() const {
415 assert(section
->outputSec
&& section
->outputSec
->sectionSym
);
416 return section
->outputSec
->sectionSym
;
419 void LazySymbol::fetch() { cast
<ArchiveFile
>(file
)->addMember(&archiveSymbol
); }
421 void LazySymbol::setWeak() {
422 flags
|= (flags
& ~WASM_SYMBOL_BINDING_MASK
) | WASM_SYMBOL_BINDING_WEAK
;
425 MemoryBufferRef
LazySymbol::getMemberBuffer() {
427 CHECK(archiveSymbol
.getMember(),
428 "could not get the member for symbol " + toString(*this));
430 return CHECK(c
.getMemoryBufferRef(),
431 "could not get the buffer for the member defining symbol " +
435 void printTraceSymbolUndefined(StringRef name
, const InputFile
* file
) {
436 message(toString(file
) + ": reference to " + name
);
439 // Print out a log message for --trace-symbol.
440 void printTraceSymbol(Symbol
*sym
) {
441 // Undefined symbols are traced via printTraceSymbolUndefined
442 if (sym
->isUndefined())
447 s
= ": lazy definition of ";
449 s
= ": definition of ";
451 message(toString(sym
->getFile()) + s
+ sym
->getName());
454 const char *defaultModule
= "env";
455 const char *functionTableName
= "__indirect_function_table";