[llvm-branch-commits] [lld] release/20.x: [wasm-ld] Refactor WasmSym from static globals to per-link context (#134970) (PR #137620)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Apr 28 04:43:11 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Anutosh Bhat (anutosh491)
<details>
<summary>Changes</summary>
Backport : https://github.com/llvm/llvm-project/commit/9cbbb74d370c09e13b8412f21dccb7d2c4afc6a4
---
Patch is 44.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/137620.diff
9 Files Affected:
- (modified) lld/wasm/Config.h (+110)
- (modified) lld/wasm/Driver.cpp (+34-30)
- (modified) lld/wasm/InputChunks.cpp (+5-5)
- (modified) lld/wasm/MarkLive.cpp (+3-3)
- (modified) lld/wasm/OutputSections.cpp (+2-2)
- (modified) lld/wasm/Symbols.cpp (-25)
- (modified) lld/wasm/Symbols.h (-99)
- (modified) lld/wasm/SyntheticSections.cpp (+14-18)
- (modified) lld/wasm/Writer.cpp (+94-93)
``````````diff
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index 1fa6c42d9cd86..71dabaedb8a8c 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -32,6 +32,11 @@ class InputTable;
class InputGlobal;
class InputFunction;
class Symbol;
+class DefinedData;
+class GlobalSymbol;
+class DefinedFunction;
+class UndefinedGlobal;
+class TableSymbol;
// For --unresolved-symbols.
enum class UnresolvedPolicy { ReportError, Warn, Ignore, ImportDynamic };
@@ -139,6 +144,111 @@ struct Ctx {
llvm::SmallVector<InputGlobal *, 0> syntheticGlobals;
llvm::SmallVector<InputTable *, 0> syntheticTables;
+ // linker-generated symbols
+ struct WasmSym {
+ // __global_base
+ // Symbol marking the start of the global section.
+ DefinedData *globalBase;
+
+ // __stack_pointer/__stack_low/__stack_high
+ // Global that holds current value of stack pointer and data symbols marking
+ // the start and end of the stack region. stackPointer is initialized to
+ // stackHigh and grows downwards towards stackLow
+ GlobalSymbol *stackPointer;
+ DefinedData *stackLow;
+ DefinedData *stackHigh;
+
+ // __tls_base
+ // Global that holds the address of the base of the current thread's
+ // TLS block.
+ GlobalSymbol *tlsBase;
+
+ // __tls_size
+ // Symbol whose value is the size of the TLS block.
+ GlobalSymbol *tlsSize;
+
+ // __tls_size
+ // Symbol whose value is the alignment of the TLS block.
+ GlobalSymbol *tlsAlign;
+
+ // __data_end
+ // Symbol marking the end of the data and bss.
+ DefinedData *dataEnd;
+
+ // __heap_base/__heap_end
+ // Symbols marking the beginning and end of the "heap". It starts at the end
+ // of the data, bss and explicit stack, and extends to the end of the linear
+ // memory allocated by wasm-ld. This region of memory is not used by the
+ // linked code, so it may be used as a backing store for `sbrk` or `malloc`
+ // implementations.
+ DefinedData *heapBase;
+ DefinedData *heapEnd;
+
+ // __wasm_first_page_end
+ // A symbol whose address is the end of the first page in memory (if any).
+ DefinedData *firstPageEnd;
+
+ // __wasm_init_memory_flag
+ // Symbol whose contents are nonzero iff memory has already been
+ // initialized.
+ DefinedData *initMemoryFlag;
+
+ // __wasm_init_memory
+ // Function that initializes passive data segments during instantiation.
+ DefinedFunction *initMemory;
+
+ // __wasm_call_ctors
+ // Function that directly calls all ctors in priority order.
+ DefinedFunction *callCtors;
+
+ // __wasm_call_dtors
+ // Function that calls the libc/etc. cleanup function.
+ DefinedFunction *callDtors;
+
+ // __wasm_apply_global_relocs
+ // Function that applies relocations to wasm globals post-instantiation.
+ // Unlike __wasm_apply_data_relocs this needs to run on every thread.
+ DefinedFunction *applyGlobalRelocs;
+
+ // __wasm_apply_tls_relocs
+ // Like __wasm_apply_data_relocs but for TLS section. These must be
+ // delayed until __wasm_init_tls.
+ DefinedFunction *applyTLSRelocs;
+
+ // __wasm_apply_global_tls_relocs
+ // Like applyGlobalRelocs but for globals that hold TLS addresses. These
+ // must be delayed until __wasm_init_tls.
+ DefinedFunction *applyGlobalTLSRelocs;
+
+ // __wasm_init_tls
+ // Function that allocates thread-local storage and initializes it.
+ DefinedFunction *initTLS;
+
+ // Pointer to the function that is to be used in the start section.
+ // (normally an alias of initMemory, or applyGlobalRelocs).
+ DefinedFunction *startFunction;
+
+ // __dso_handle
+ // Symbol used in calls to __cxa_atexit to determine current DLL
+ DefinedData *dsoHandle;
+
+ // __table_base
+ // Used in PIC code for offset of indirect function table
+ UndefinedGlobal *tableBase;
+ DefinedData *definedTableBase;
+
+ // __memory_base
+ // Used in PIC code for offset of global data
+ UndefinedGlobal *memoryBase;
+ DefinedData *definedMemoryBase;
+
+ // __indirect_function_table
+ // Used as an address space for function pointers, with each function that
+ // is used as a function pointer being allocated a slot.
+ TableSymbol *indirectFunctionTable;
+ };
+ WasmSym sym;
+
// True if we are creating position-independent code.
bool isPic = false;
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index c3a74dde6480e..a6e6f90e56dc3 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -70,6 +70,7 @@ void Ctx::reset() {
isPic = false;
legacyFunctionTable = false;
emitBssSegments = false;
+ sym = WasmSym{};
}
namespace {
@@ -941,14 +942,14 @@ static void createSyntheticSymbols() {
true};
static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64,
true};
- WasmSym::callCtors = symtab->addSyntheticFunction(
+ ctx.sym.callCtors = symtab->addSyntheticFunction(
"__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));
bool is64 = ctx.arg.is64.value_or(false);
if (ctx.isPic) {
- WasmSym::stackPointer =
+ ctx.sym.stackPointer =
createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false)
? &mutableGlobalTypeI64
: &mutableGlobalTypeI32);
@@ -958,25 +959,24 @@ static void createSyntheticSymbols() {
// See:
// https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
auto *globalType = is64 ? &globalTypeI64 : &globalTypeI32;
- WasmSym::memoryBase = createUndefinedGlobal("__memory_base", globalType);
- WasmSym::tableBase = createUndefinedGlobal("__table_base", globalType);
- WasmSym::memoryBase->markLive();
- WasmSym::tableBase->markLive();
+ ctx.sym.memoryBase = createUndefinedGlobal("__memory_base", globalType);
+ ctx.sym.tableBase = createUndefinedGlobal("__table_base", globalType);
+ ctx.sym.memoryBase->markLive();
+ ctx.sym.tableBase->markLive();
} else {
// For non-PIC code
- WasmSym::stackPointer = createGlobalVariable("__stack_pointer", true);
- WasmSym::stackPointer->markLive();
+ ctx.sym.stackPointer = createGlobalVariable("__stack_pointer", true);
+ ctx.sym.stackPointer->markLive();
}
if (ctx.arg.sharedMemory) {
- WasmSym::tlsBase = createGlobalVariable("__tls_base", true);
- WasmSym::tlsSize = createGlobalVariable("__tls_size", false);
- WasmSym::tlsAlign = createGlobalVariable("__tls_align", false);
- WasmSym::initTLS = symtab->addSyntheticFunction(
+ ctx.sym.tlsBase = createGlobalVariable("__tls_base", true);
+ ctx.sym.tlsSize = createGlobalVariable("__tls_size", false);
+ ctx.sym.tlsAlign = createGlobalVariable("__tls_align", false);
+ ctx.sym.initTLS = symtab->addSyntheticFunction(
"__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN,
- make<SyntheticFunction>(
- is64 ? i64ArgSignature : i32ArgSignature,
- "__wasm_init_tls"));
+ make<SyntheticFunction>(is64 ? i64ArgSignature : i32ArgSignature,
+ "__wasm_init_tls"));
}
}
@@ -984,21 +984,25 @@ static void createOptionalSymbols() {
if (ctx.arg.relocatable)
return;
- WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
+ ctx.sym.dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
if (!ctx.arg.shared)
- WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end");
+ ctx.sym.dataEnd = symtab->addOptionalDataSymbol("__data_end");
if (!ctx.isPic) {
- WasmSym::stackLow = symtab->addOptionalDataSymbol("__stack_low");
- WasmSym::stackHigh = symtab->addOptionalDataSymbol("__stack_high");
- WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base");
- WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base");
- WasmSym::heapEnd = symtab->addOptionalDataSymbol("__heap_end");
- WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
- WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base");
+ ctx.sym.stackLow = symtab->addOptionalDataSymbol("__stack_low");
+ ctx.sym.stackHigh = symtab->addOptionalDataSymbol("__stack_high");
+ ctx.sym.globalBase = symtab->addOptionalDataSymbol("__global_base");
+ ctx.sym.heapBase = symtab->addOptionalDataSymbol("__heap_base");
+ ctx.sym.heapEnd = symtab->addOptionalDataSymbol("__heap_end");
+ ctx.sym.definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
+ ctx.sym.definedTableBase = symtab->addOptionalDataSymbol("__table_base");
}
+ ctx.sym.firstPageEnd = symtab->addOptionalDataSymbol("__wasm_first_page_end");
+ if (ctx.sym.firstPageEnd)
+ ctx.sym.firstPageEnd->setVA(ctx.arg.pageSize);
+
// For non-shared memory programs we still need to define __tls_base since we
// allow object files built with TLS to be linked into single threaded
// programs, and such object files can contain references to this symbol.
@@ -1009,7 +1013,7 @@ static void createOptionalSymbols() {
// __tls_size and __tls_align are not needed in this case since they are only
// needed for __wasm_init_tls (which we do not create in this case).
if (!ctx.arg.sharedMemory)
- WasmSym::tlsBase = createOptionalGlobal("__tls_base", false);
+ ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false);
}
static void processStubLibrariesPreLTO() {
@@ -1384,9 +1388,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// by libc/etc., because destructors are registered dynamically with
// `__cxa_atexit` and friends.
if (!ctx.arg.relocatable && !ctx.arg.shared &&
- !WasmSym::callCtors->isUsedInRegularObj &&
- WasmSym::callCtors->getName() != ctx.arg.entry &&
- !ctx.arg.exportedSymbols.count(WasmSym::callCtors->getName())) {
+ !ctx.sym.callCtors->isUsedInRegularObj &&
+ ctx.sym.callCtors->getName() != ctx.arg.entry &&
+ !ctx.arg.exportedSymbols.count(ctx.sym.callCtors->getName())) {
if (Symbol *callDtors =
handleUndefined("__wasm_call_dtors", "<internal>")) {
if (auto *callDtorsFunc = dyn_cast<DefinedFunction>(callDtors)) {
@@ -1395,7 +1399,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
!callDtorsFunc->signature->Returns.empty())) {
error("__wasm_call_dtors must have no argument or return values");
}
- WasmSym::callDtors = callDtorsFunc;
+ ctx.sym.callDtors = callDtorsFunc;
} else {
error("__wasm_call_dtors must be a function");
}
@@ -1488,7 +1492,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
markLive();
// Provide the indirect function table if needed.
- WasmSym::indirectFunctionTable =
+ ctx.sym.indirectFunctionTable =
symtab->resolveIndirectFunctionTable(/*required =*/false);
if (errorCount())
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index ccdc92f5c8d71..0e6c4e691be10 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -397,9 +397,9 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
if (ctx.isPic) {
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
if (isTLS())
- writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "tls_base");
+ writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "tls_base");
else
- writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
+ writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "memory_base");
writeU8(os, opcode_ptr_add, "ADD");
}
@@ -422,12 +422,12 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
}
} else {
assert(ctx.isPic);
- const GlobalSymbol* baseSymbol = WasmSym::memoryBase;
+ const GlobalSymbol *baseSymbol = ctx.sym.memoryBase;
if (rel.Type == R_WASM_TABLE_INDEX_I32 ||
rel.Type == R_WASM_TABLE_INDEX_I64)
- baseSymbol = WasmSym::tableBase;
+ baseSymbol = ctx.sym.tableBase;
else if (sym->isTLS())
- baseSymbol = WasmSym::tlsBase;
+ baseSymbol = ctx.sym.tlsBase;
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
writeU8(os, opcode_reloc_const, "CONST");
diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp
index 13c7a3d894fe3..2b2cf19f14b30 100644
--- a/lld/wasm/MarkLive.cpp
+++ b/lld/wasm/MarkLive.cpp
@@ -114,8 +114,8 @@ void MarkLive::run() {
if (sym->isNoStrip() || sym->isExported())
enqueue(sym);
- if (WasmSym::callDtors)
- enqueue(WasmSym::callDtors);
+ if (ctx.sym.callDtors)
+ enqueue(ctx.sym.callDtors);
for (const ObjFile *obj : ctx.objectFiles)
if (obj->isLive()) {
@@ -131,7 +131,7 @@ void MarkLive::run() {
// If we have any non-discarded init functions, mark `__wasm_call_ctors` as
// live so that we assign it an index and call it.
if (isCallCtorsLive())
- WasmSym::callCtors->markLive();
+ ctx.sym.callCtors->markLive();
}
void MarkLive::mark() {
diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp
index 95f7ecc29de6b..4142a913c8cbf 100644
--- a/lld/wasm/OutputSections.cpp
+++ b/lld/wasm/OutputSections.cpp
@@ -123,7 +123,7 @@ void DataSection::finalizeContents() {
if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
if (ctx.isPic && ctx.arg.extendedConst) {
writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get");
- writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
+ writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(),
"literal (global index)");
if (segment->startVA) {
writePtrConst(os, segment->startVA, is64, "offset");
@@ -136,7 +136,7 @@ void DataSection::finalizeContents() {
if (ctx.isPic) {
assert(segment->startVA == 0);
initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
- initExpr.Inst.Value.Global = WasmSym::memoryBase->getGlobalIndex();
+ initExpr.Inst.Value.Global = ctx.sym.memoryBase->getGlobalIndex();
} else {
initExpr = intConst(segment->startVA, is64);
}
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index a687fd6d6c4ef..92a933ecbb024 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -77,31 +77,6 @@ std::string toString(wasm::Symbol::Kind kind) {
}
namespace wasm {
-DefinedFunction *WasmSym::callCtors;
-DefinedFunction *WasmSym::callDtors;
-DefinedFunction *WasmSym::initMemory;
-DefinedFunction *WasmSym::applyGlobalRelocs;
-DefinedFunction *WasmSym::applyTLSRelocs;
-DefinedFunction *WasmSym::applyGlobalTLSRelocs;
-DefinedFunction *WasmSym::initTLS;
-DefinedFunction *WasmSym::startFunction;
-DefinedData *WasmSym::dsoHandle;
-DefinedData *WasmSym::dataEnd;
-DefinedData *WasmSym::globalBase;
-DefinedData *WasmSym::heapBase;
-DefinedData *WasmSym::heapEnd;
-DefinedData *WasmSym::initMemoryFlag;
-GlobalSymbol *WasmSym::stackPointer;
-DefinedData *WasmSym::stackLow;
-DefinedData *WasmSym::stackHigh;
-GlobalSymbol *WasmSym::tlsBase;
-GlobalSymbol *WasmSym::tlsSize;
-GlobalSymbol *WasmSym::tlsAlign;
-UndefinedGlobal *WasmSym::tableBase;
-DefinedData *WasmSym::definedTableBase;
-UndefinedGlobal *WasmSym::memoryBase;
-DefinedData *WasmSym::definedMemoryBase;
-TableSymbol *WasmSym::indirectFunctionTable;
WasmSymbolType Symbol::getWasmType() const {
if (isa<FunctionSymbol>(this))
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index b409fffc50a6c..55ee21939ce07 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -537,105 +537,6 @@ class LazySymbol : public Symbol {
const WasmSignature *signature = nullptr;
};
-// linker-generated symbols
-struct WasmSym {
- // __global_base
- // Symbol marking the start of the global section.
- static DefinedData *globalBase;
-
- // __stack_pointer/__stack_low/__stack_high
- // Global that holds current value of stack pointer and data symbols marking
- // the start and end of the stack region. stackPointer is initialized to
- // stackHigh and grows downwards towards stackLow
- static GlobalSymbol *stackPointer;
- static DefinedData *stackLow;
- static DefinedData *stackHigh;
-
- // __tls_base
- // Global that holds the address of the base of the current thread's
- // TLS block.
- static GlobalSymbol *tlsBase;
-
- // __tls_size
- // Symbol whose value is the size of the TLS block.
- static GlobalSymbol *tlsSize;
-
- // __tls_size
- // Symbol whose value is the alignment of the TLS block.
- static GlobalSymbol *tlsAlign;
-
- // __data_end
- // Symbol marking the end of the data and bss.
- static DefinedData *dataEnd;
-
- // __heap_base/__heap_end
- // Symbols marking the beginning and end of the "heap". It starts at the end
- // of the data, bss and explicit stack, and extends to the end of the linear
- // memory allocated by wasm-ld. This region of memory is not used by the
- // linked code, so it may be used as a backing store for `sbrk` or `malloc`
- // implementations.
- static DefinedData *heapBase;
- static DefinedData *heapEnd;
-
- // __wasm_init_memory_flag
- // Symbol whose contents are nonzero iff memory has already been initialized.
- static DefinedData *initMemoryFlag;
-
- // __wasm_init_memory
- // Function that initializes passive data segments during instantiation.
- static DefinedFunction *initMemory;
-
- // __wasm_call_ctors
- // Function that directly calls all ctors in priority order.
- static DefinedFunction *callCtors;
-
- // __wasm_call_dtors
- // Function that calls the libc/etc. cleanup function.
- static DefinedFunction *callDtors;
-
- // __wasm_apply_global_relocs
- // Function that applies relocations to wasm globals post-instantiation.
- // Unlike __wasm_apply_data_relocs this needs to run on every thread.
- static DefinedFunction *applyGlobalRelocs;
-
- // __wasm_apply_tls_relocs
- // Like __wasm_apply_data_relocs but for TLS section. These must be
- // delayed until __wasm_init_tls.
- static DefinedFunction *applyTLSRelocs;
-
- // __wasm_apply_global_tls_relocs
- // Like applyGlobalRelocs but for globals that hold TLS addresses. These
- // must be delayed until __wasm_init_tls.
- static DefinedFunction *applyGlobalTLSRelocs;
-
- // __wasm_init_tls
- // Function that allocates thread-local storage and initializes it.
- static DefinedFunction *initTLS;
-
- // Pointer to the function that is to be used in the start section.
- // (normally an alias of initMemory, or applyGlobalRelocs).
- static DefinedFunction *startFunction;
-
- // __dso_handle
- // Symbol used in calls to __cxa_atexit to determine current DLL
- static DefinedData *dsoHandle;
-
- // __table_base
- // Used in PIC code for offset of indirect function table
- static UndefinedGlobal *tableBase;
- static DefinedData *definedTableBase;
-
- // __memory_base
- // Used in PIC code for offset of global data
- static UndefinedGlobal *memoryBase;
- static DefinedData *definedMemoryBase;
-
- // __indirect_function_table
- // Used as an address space for function pointers, with each function that is
- // used as a function pointer being allocated a slot.
- static TableSymbol *indirectFunctionTable;
-};
-
// A buffer class that is large enough to hold any Symbol-derived
// object. We allocate memory using this class and instantiate a symbol
// using the placement new.
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index 7fb44b9f0c009..0e2aa57e9048e 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -319,8 +319,8 @@ void TableSection::addTable(InputTable *table) {
// Some inputs require that the indirect function table be assigned to table
// number 0.
if (ctx.legacyFunctionTable &&
- isa<DefinedTable>(WasmSym::indirectFunctionTable) &&
- cast<DefinedTable>(WasmSym::indirectFunctionTable)->table == table) {
+ isa<DefinedTable>(ctx.sym.indirectFunctionTable) &&
+ cast<DefinedTable>(ctx.sym.indirectFunctionTable)->table == table) {
if (out.importSec->getNumImportedTables()) {
// Alack! Some other i...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/137620
More information about the llvm-branch-commits
mailing list