diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index ffc5b84ca38b0..9d903e0c799db 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 }; @@ -141,6 +146,111 @@ struct Ctx { llvm::SmallVector syntheticGlobals; llvm::SmallVector 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 de976947474e1..80e9a3ead2a44 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 { @@ -945,14 +946,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(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); @@ -962,25 +963,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( - is64 ? i64ArgSignature : i32ArgSignature, - "__wasm_init_tls")); + make(is64 ? i64ArgSignature : i32ArgSignature, + "__wasm_init_tls")); } } @@ -988,25 +988,24 @@ 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"); } - WasmSym::firstPageEnd = - symtab->addOptionalDataSymbol("__wasm_first_page_end"); - if (WasmSym::firstPageEnd) - WasmSym::firstPageEnd->setVA(ctx.arg.pageSize); + 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 @@ -1018,7 +1017,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() { @@ -1393,9 +1392,9 @@ void LinkerDriver::linkerMain(ArrayRef 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", "")) { if (auto *callDtorsFunc = dyn_cast(callDtors)) { @@ -1404,7 +1403,7 @@ void LinkerDriver::linkerMain(ArrayRef 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"); } @@ -1497,7 +1496,7 @@ void LinkerDriver::linkerMain(ArrayRef 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 3668697382238..ffab83e636392 100644 --- a/lld/wasm/InputChunks.cpp +++ b/lld/wasm/InputChunks.cpp @@ -411,9 +411,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"); } @@ -436,12 +436,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 5038cd8ea965b..cd80254a18d5c 100644 --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -124,7 +124,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"); @@ -137,7 +137,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 af5ecf4f38f73..f2040441e6257 100644 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -77,32 +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; -DefinedData *WasmSym::firstPageEnd; -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(this)) diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index 03a74da7230d0..55ee21939ce07 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -537,109 +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_first_page_end - // A symbol whose address is the end of the first page in memory (if any). - static DefinedData *firstPageEnd; - - // __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 c88a6f742c35e..76719596c62e0 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -328,8 +328,8 @@ void TableSection::addTable(InputTable *table) { // Some inputs require that the indirect function table be assigned to table // number 0. if (ctx.legacyFunctionTable && - isa(WasmSym::indirectFunctionTable) && - cast(WasmSym::indirectFunctionTable)->table == table) { + isa(ctx.sym.indirectFunctionTable) && + cast(ctx.sym.indirectFunctionTable)->table == table) { if (out.importSec->getNumImportedTables()) { // Alack! Some other input imported a table, meaning that we are unable // to assign table number 0 to the indirect function table. @@ -408,8 +408,8 @@ void GlobalSection::assignIndexes() { } static void ensureIndirectFunctionTable() { - if (!WasmSym::indirectFunctionTable) - WasmSym::indirectFunctionTable = + if (!ctx.sym.indirectFunctionTable) + ctx.sym.indirectFunctionTable = symtab->resolveIndirectFunctionTable(/*required =*/true); } @@ -443,10 +443,9 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { // Get __memory_base writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); if (sym->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"); // Add the virtual address of the data symbol writeU8(os, opcode_ptr_const, "CONST"); @@ -456,7 +455,7 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { continue; // Get __table_base writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); - writeUleb128(os, WasmSym::tableBase->getGlobalIndex(), "__table_base"); + writeUleb128(os, ctx.sym.tableBase->getGlobalIndex(), "__table_base"); // Add the table index to __table_base writeU8(os, opcode_ptr_const, "CONST"); @@ -503,13 +502,13 @@ void GlobalSection::writeBody() { if (ctx.arg.extendedConst && ctx.isPic) { if (auto *d = dyn_cast(sym)) { if (!sym->isTLS()) { - globalIdx = WasmSym::memoryBase->getGlobalIndex(); + globalIdx = ctx.sym.memoryBase->getGlobalIndex(); offset = d->getVA(); useExtendedConst = true; } } else if (auto *f = dyn_cast(sym)) { if (!sym->isStub) { - globalIdx = WasmSym::tableBase->getGlobalIndex(); + globalIdx = ctx.sym.tableBase->getGlobalIndex(); offset = f->getTableIndex(); useExtendedConst = true; } @@ -563,14 +562,11 @@ void ExportSection::writeBody() { writeExport(os, export_); } -bool StartSection::isNeeded() const { - return WasmSym::startFunction != nullptr; -} +bool StartSection::isNeeded() const { return ctx.sym.startFunction != nullptr; } void StartSection::writeBody() { raw_ostream &os = bodyOutputStream; - writeUleb128(os, WasmSym::startFunction->getFunctionIndex(), - "function index"); + writeUleb128(os, ctx.sym.startFunction->getFunctionIndex(), "function index"); } void ElemSection::addEntry(FunctionSymbol *sym) { @@ -586,9 +582,9 @@ void ElemSection::addEntry(FunctionSymbol *sym) { void ElemSection::writeBody() { raw_ostream &os = bodyOutputStream; - assert(WasmSym::indirectFunctionTable); + assert(ctx.sym.indirectFunctionTable); writeUleb128(os, 1, "segment count"); - uint32_t tableNumber = WasmSym::indirectFunctionTable->getTableNumber(); + uint32_t tableNumber = ctx.sym.indirectFunctionTable->getTableNumber(); uint32_t flags = 0; if (tableNumber) flags |= WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER; @@ -600,7 +596,7 @@ void ElemSection::writeBody() { initExpr.Extended = false; if (ctx.isPic) { initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET; - initExpr.Inst.Value.Global = WasmSym::tableBase->getGlobalIndex(); + initExpr.Inst.Value.Global = ctx.sym.tableBase->getGlobalIndex(); } else { bool is64 = ctx.arg.is64.value_or(false); initExpr = intConst(ctx.arg.tableBase, is64); diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index f4ba182ee5079..3cc3e0d498979 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -346,16 +346,16 @@ void Writer::layoutMemory() { if (ctx.arg.relocatable || ctx.isPic) return; memoryPtr = alignTo(memoryPtr, stackAlignment); - if (WasmSym::stackLow) - WasmSym::stackLow->setVA(memoryPtr); + if (ctx.sym.stackLow) + ctx.sym.stackLow->setVA(memoryPtr); if (ctx.arg.zStackSize != alignTo(ctx.arg.zStackSize, stackAlignment)) error("stack size must be " + Twine(stackAlignment) + "-byte aligned"); log("mem: stack size = " + Twine(ctx.arg.zStackSize)); log("mem: stack base = " + Twine(memoryPtr)); memoryPtr += ctx.arg.zStackSize; - setGlobalPtr(cast(WasmSym::stackPointer), memoryPtr); - if (WasmSym::stackHigh) - WasmSym::stackHigh->setVA(memoryPtr); + setGlobalPtr(cast(ctx.sym.stackPointer), memoryPtr); + if (ctx.sym.stackHigh) + ctx.sym.stackHigh->setVA(memoryPtr); log("mem: stack top = " + Twine(memoryPtr)); }; @@ -373,15 +373,15 @@ void Writer::layoutMemory() { } log("mem: global base = " + Twine(memoryPtr)); - if (WasmSym::globalBase) - WasmSym::globalBase->setVA(memoryPtr); + if (ctx.sym.globalBase) + ctx.sym.globalBase->setVA(memoryPtr); uint64_t dataStart = memoryPtr; // Arbitrarily set __dso_handle handle to point to the start of the data // segments. - if (WasmSym::dsoHandle) - WasmSym::dsoHandle->setVA(dataStart); + if (ctx.sym.dsoHandle) + ctx.sym.dsoHandle->setVA(dataStart); out.dylinkSec->memAlign = 0; for (OutputSegment *seg : segments) { @@ -392,16 +392,16 @@ void Writer::layoutMemory() { memoryPtr, seg->size, seg->alignment)); if (!ctx.arg.relocatable && seg->isTLS()) { - if (WasmSym::tlsSize) { - auto *tlsSize = cast(WasmSym::tlsSize); + if (ctx.sym.tlsSize) { + auto *tlsSize = cast(ctx.sym.tlsSize); setGlobalPtr(tlsSize, seg->size); } - if (WasmSym::tlsAlign) { - auto *tlsAlign = cast(WasmSym::tlsAlign); + if (ctx.sym.tlsAlign) { + auto *tlsAlign = cast(ctx.sym.tlsAlign); setGlobalPtr(tlsAlign, int64_t{1} << seg->alignment); } - if (!ctx.arg.sharedMemory && WasmSym::tlsBase) { - auto *tlsBase = cast(WasmSym::tlsBase); + if (!ctx.arg.sharedMemory && ctx.sym.tlsBase) { + auto *tlsBase = cast(ctx.sym.tlsBase); setGlobalPtr(tlsBase, memoryPtr); } } @@ -412,17 +412,17 @@ void Writer::layoutMemory() { // Make space for the memory initialization flag if (ctx.arg.sharedMemory && hasPassiveInitializedSegments()) { memoryPtr = alignTo(memoryPtr, 4); - WasmSym::initMemoryFlag = symtab->addSyntheticDataSymbol( + ctx.sym.initMemoryFlag = symtab->addSyntheticDataSymbol( "__wasm_init_memory_flag", WASM_SYMBOL_VISIBILITY_HIDDEN); - WasmSym::initMemoryFlag->markLive(); - WasmSym::initMemoryFlag->setVA(memoryPtr); + ctx.sym.initMemoryFlag->markLive(); + ctx.sym.initMemoryFlag->setVA(memoryPtr); log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", "__wasm_init_memory_flag", memoryPtr, 4, 4)); memoryPtr += 4; } - if (WasmSym::dataEnd) - WasmSym::dataEnd->setVA(memoryPtr); + if (ctx.sym.dataEnd) + ctx.sym.dataEnd->setVA(memoryPtr); uint64_t staticDataSize = memoryPtr - dataStart; log("mem: static data = " + Twine(staticDataSize)); @@ -432,7 +432,7 @@ void Writer::layoutMemory() { if (!ctx.arg.stackFirst) placeStack(); - if (WasmSym::heapBase) { + if (ctx.sym.heapBase) { // Set `__heap_base` to follow the end of the stack or global data. The // fact that this comes last means that a malloc/brk implementation can // grow the heap at runtime. @@ -440,7 +440,7 @@ void Writer::layoutMemory() { // __heap_base to be aligned already. memoryPtr = alignTo(memoryPtr, heapAlignment); log("mem: heap base = " + Twine(memoryPtr)); - WasmSym::heapBase->setVA(memoryPtr); + ctx.sym.heapBase->setVA(memoryPtr); } uint64_t maxMemorySetting = 1ULL << 32; @@ -474,12 +474,12 @@ void Writer::layoutMemory() { out.memorySec->numMemoryPages = memoryPtr / ctx.arg.pageSize; log("mem: total pages = " + Twine(out.memorySec->numMemoryPages)); - if (WasmSym::heapEnd) { + if (ctx.sym.heapEnd) { // Set `__heap_end` to follow the end of the statically allocated linear // memory. The fact that this comes last means that a malloc/brk // implementation can grow the heap at runtime. log("mem: heap end = " + Twine(memoryPtr)); - WasmSym::heapEnd->setVA(memoryPtr); + ctx.sym.heapEnd->setVA(memoryPtr); } uint64_t maxMemory = 0; @@ -761,14 +761,14 @@ void Writer::calculateImports() { // Some inputs require that the indirect function table be assigned to table // number 0, so if it is present and is an import, allocate it before any // other tables. - if (WasmSym::indirectFunctionTable && - shouldImport(WasmSym::indirectFunctionTable)) - out.importSec->addImport(WasmSym::indirectFunctionTable); + if (ctx.sym.indirectFunctionTable && + shouldImport(ctx.sym.indirectFunctionTable)) + out.importSec->addImport(ctx.sym.indirectFunctionTable); for (Symbol *sym : symtab->symbols()) { if (!shouldImport(sym)) continue; - if (sym == WasmSym::indirectFunctionTable) + if (sym == ctx.sym.indirectFunctionTable) continue; LLVM_DEBUG(dbgs() << "import: " << sym->getName() << "\n"); out.importSec->addImport(sym); @@ -882,7 +882,7 @@ void Writer::createCommandExportWrappers() { // If there are no ctors and there's no libc `__wasm_call_dtors` to // call, don't wrap the exports. - if (initFunctions.empty() && WasmSym::callDtors == nullptr) + if (initFunctions.empty() && ctx.sym.callDtors == nullptr) return; std::vector toWrap; @@ -922,27 +922,27 @@ void Writer::createCommandExportWrappers() { } static void finalizeIndirectFunctionTable() { - if (!WasmSym::indirectFunctionTable) + if (!ctx.sym.indirectFunctionTable) return; - if (shouldImport(WasmSym::indirectFunctionTable) && - !WasmSym::indirectFunctionTable->hasTableNumber()) { + if (shouldImport(ctx.sym.indirectFunctionTable) && + !ctx.sym.indirectFunctionTable->hasTableNumber()) { // Processing -Bsymbolic relocations resulted in a late requirement that the // indirect function table be present, and we are running in --import-table // mode. Add the table now to the imports section. Otherwise it will be // added to the tables section later in assignIndexes. - out.importSec->addImport(WasmSym::indirectFunctionTable); + out.importSec->addImport(ctx.sym.indirectFunctionTable); } uint32_t tableSize = ctx.arg.tableBase + out.elemSec->numEntries(); WasmLimits limits = {0, tableSize, 0, 0}; - if (WasmSym::indirectFunctionTable->isDefined() && !ctx.arg.growableTable) { + if (ctx.sym.indirectFunctionTable->isDefined() && !ctx.arg.growableTable) { limits.Flags |= WASM_LIMITS_FLAG_HAS_MAX; limits.Maximum = limits.Minimum; } if (ctx.arg.is64.value_or(false)) limits.Flags |= WASM_LIMITS_FLAG_IS_64; - WasmSym::indirectFunctionTable->setLimits(limits); + ctx.sym.indirectFunctionTable->setLimits(limits); } static void scanRelocations() { @@ -1150,26 +1150,26 @@ void Writer::createSyntheticInitFunctions() { // We also initialize bss segments (using memory.fill) as part of this // function. if (hasPassiveInitializedSegments()) { - WasmSym::initMemory = symtab->addSyntheticFunction( + ctx.sym.initMemory = symtab->addSyntheticFunction( "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_init_memory")); - WasmSym::initMemory->markLive(); + ctx.sym.initMemory->markLive(); if (ctx.arg.sharedMemory) { // This global is assigned during __wasm_init_memory in the shared memory // case. - WasmSym::tlsBase->markLive(); + ctx.sym.tlsBase->markLive(); } } if (ctx.arg.sharedMemory) { if (out.globalSec->needsTLSRelocations()) { - WasmSym::applyGlobalTLSRelocs = symtab->addSyntheticFunction( + ctx.sym.applyGlobalTLSRelocs = symtab->addSyntheticFunction( "__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_apply_global_tls_relocs")); - WasmSym::applyGlobalTLSRelocs->markLive(); + ctx.sym.applyGlobalTLSRelocs->markLive(); // TLS relocations depend on the __tls_base symbols - WasmSym::tlsBase->markLive(); + ctx.sym.tlsBase->markLive(); } auto hasTLSRelocs = [](const OutputSegment *segment) { @@ -1180,40 +1180,39 @@ void Writer::createSyntheticInitFunctions() { return false; }; if (llvm::any_of(segments, hasTLSRelocs)) { - WasmSym::applyTLSRelocs = symtab->addSyntheticFunction( + ctx.sym.applyTLSRelocs = symtab->addSyntheticFunction( "__wasm_apply_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, - make(nullSignature, - "__wasm_apply_tls_relocs")); - WasmSym::applyTLSRelocs->markLive(); + make(nullSignature, "__wasm_apply_tls_relocs")); + ctx.sym.applyTLSRelocs->markLive(); } } if (ctx.isPic && out.globalSec->needsRelocations()) { - WasmSym::applyGlobalRelocs = symtab->addSyntheticFunction( + ctx.sym.applyGlobalRelocs = symtab->addSyntheticFunction( "__wasm_apply_global_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_apply_global_relocs")); - WasmSym::applyGlobalRelocs->markLive(); + ctx.sym.applyGlobalRelocs->markLive(); } // If there is only one start function we can just use that function // itself as the Wasm start function, otherwise we need to synthesize // a new function to call them in sequence. - if (WasmSym::applyGlobalRelocs && WasmSym::initMemory) { - WasmSym::startFunction = symtab->addSyntheticFunction( + if (ctx.sym.applyGlobalRelocs && ctx.sym.initMemory) { + ctx.sym.startFunction = symtab->addSyntheticFunction( "__wasm_start", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_start")); - WasmSym::startFunction->markLive(); + ctx.sym.startFunction->markLive(); } } void Writer::createInitMemoryFunction() { LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n"); - assert(WasmSym::initMemory); + assert(ctx.sym.initMemory); assert(hasPassiveInitializedSegments()); uint64_t flagAddress; if (ctx.arg.sharedMemory) { - assert(WasmSym::initMemoryFlag); - flagAddress = WasmSym::initMemoryFlag->getVA(); + assert(ctx.sym.initMemoryFlag); + flagAddress = ctx.sym.initMemoryFlag->getVA(); } bool is64 = ctx.arg.is64.value_or(false); std::string bodyContent; @@ -1286,7 +1285,7 @@ void Writer::createInitMemoryFunction() { writeUleb128(os, 2, "local count"); writeU8(os, is64 ? WASM_TYPE_I64 : WASM_TYPE_I32, "address type"); writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); - writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base"); + writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "memory_base"); writePtrConst(os, flagAddress, is64, "flag address"); writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "add"); writeU8(os, WASM_OPCODE_LOCAL_SET, "local.set"); @@ -1333,7 +1332,7 @@ void Writer::createInitMemoryFunction() { writePtrConst(os, s->startVA, is64, "destination address"); if (ctx.isPic) { writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); - writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), + writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "__memory_base"); writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "i32.add"); @@ -1351,8 +1350,7 @@ void Writer::createInitMemoryFunction() { writePtrConst(os, s->startVA, is64, "destination address"); } writeU8(os, WASM_OPCODE_GLOBAL_SET, "GLOBAL_SET"); - writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), - "__tls_base"); + writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); if (ctx.isPic) { writeU8(os, WASM_OPCODE_LOCAL_GET, "local.tee"); writeUleb128(os, 1, "local 1"); @@ -1428,30 +1426,30 @@ void Writer::createInitMemoryFunction() { writeU8(os, WASM_OPCODE_END, "END"); } - createFunction(WasmSym::initMemory, bodyContent); + createFunction(ctx.sym.initMemory, bodyContent); } void Writer::createStartFunction() { // If the start function exists when we have more than one function to call. - if (WasmSym::initMemory && WasmSym::applyGlobalRelocs) { - assert(WasmSym::startFunction); + if (ctx.sym.initMemory && ctx.sym.applyGlobalRelocs) { + assert(ctx.sym.startFunction); std::string bodyContent; { raw_string_ostream os(bodyContent); writeUleb128(os, 0, "num locals"); writeU8(os, WASM_OPCODE_CALL, "CALL"); - writeUleb128(os, WasmSym::applyGlobalRelocs->getFunctionIndex(), + writeUleb128(os, ctx.sym.applyGlobalRelocs->getFunctionIndex(), "function index"); writeU8(os, WASM_OPCODE_CALL, "CALL"); - writeUleb128(os, WasmSym::initMemory->getFunctionIndex(), + writeUleb128(os, ctx.sym.initMemory->getFunctionIndex(), "function index"); writeU8(os, WASM_OPCODE_END, "END"); } - createFunction(WasmSym::startFunction, bodyContent); - } else if (WasmSym::initMemory) { - WasmSym::startFunction = WasmSym::initMemory; - } else if (WasmSym::applyGlobalRelocs) { - WasmSym::startFunction = WasmSym::applyGlobalRelocs; + createFunction(ctx.sym.startFunction, bodyContent); + } else if (ctx.sym.initMemory) { + ctx.sym.startFunction = ctx.sym.initMemory; + } else if (ctx.sym.applyGlobalRelocs) { + ctx.sym.startFunction = ctx.sym.applyGlobalRelocs; } } @@ -1505,7 +1503,7 @@ void Writer::createApplyTLSRelocationsFunction() { writeU8(os, WASM_OPCODE_END, "END"); } - createFunction(WasmSym::applyTLSRelocs, bodyContent); + createFunction(ctx.sym.applyTLSRelocs, bodyContent); } // Similar to createApplyDataRelocationsFunction but generates relocation code @@ -1521,7 +1519,7 @@ void Writer::createApplyGlobalRelocationsFunction() { writeU8(os, WASM_OPCODE_END, "END"); } - createFunction(WasmSym::applyGlobalRelocs, bodyContent); + createFunction(ctx.sym.applyGlobalRelocs, bodyContent); } // Similar to createApplyGlobalRelocationsFunction but for @@ -1537,7 +1535,7 @@ void Writer::createApplyGlobalTLSRelocationsFunction() { writeU8(os, WASM_OPCODE_END, "END"); } - createFunction(WasmSym::applyGlobalTLSRelocs, bodyContent); + createFunction(ctx.sym.applyGlobalTLSRelocs, bodyContent); } // Create synthetic "__wasm_call_ctors" function based on ctor functions @@ -1545,7 +1543,7 @@ void Writer::createApplyGlobalTLSRelocationsFunction() { void Writer::createCallCtorsFunction() { // If __wasm_call_ctors isn't referenced, there aren't any ctors, don't // define the `__wasm_call_ctors` function. - if (!WasmSym::callCtors->isLive() && initFunctions.empty()) + if (!ctx.sym.callCtors->isLive() && initFunctions.empty()) return; // First write the body's contents to a string. @@ -1566,7 +1564,7 @@ void Writer::createCallCtorsFunction() { writeU8(os, WASM_OPCODE_END, "END"); } - createFunction(WasmSym::callCtors, bodyContent); + createFunction(ctx.sym.callCtors, bodyContent); } // Create a wrapper around a function export which calls the @@ -1581,10 +1579,9 @@ void Writer::createCommandExportWrapper(uint32_t functionIndex, // Call `__wasm_call_ctors` which call static constructors (and // applies any runtime relocations in Emscripten-style PIC mode) - if (WasmSym::callCtors->isLive()) { + if (ctx.sym.callCtors->isLive()) { writeU8(os, WASM_OPCODE_CALL, "CALL"); - writeUleb128(os, WasmSym::callCtors->getFunctionIndex(), - "function index"); + writeUleb128(os, ctx.sym.callCtors->getFunctionIndex(), "function index"); } // Call the user's code, leaving any return values on the operand stack. @@ -1596,7 +1593,7 @@ void Writer::createCommandExportWrapper(uint32_t functionIndex, writeUleb128(os, functionIndex, "function index"); // Call the function that calls the destructors. - if (DefinedFunction *callDtors = WasmSym::callDtors) { + if (DefinedFunction *callDtors = ctx.sym.callDtors) { writeU8(os, WASM_OPCODE_CALL, "CALL"); writeUleb128(os, callDtors->getFunctionIndex(), "function index"); } @@ -1627,7 +1624,7 @@ void Writer::createInitTLSFunction() { writeUleb128(os, 0, "local index"); writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); - writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "global index"); + writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index"); // FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend op. writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); @@ -1643,28 +1640,28 @@ void Writer::createInitTLSFunction() { writeU8(os, 0, "memory index immediate"); } - if (WasmSym::applyTLSRelocs) { + if (ctx.sym.applyTLSRelocs) { writeU8(os, WASM_OPCODE_CALL, "CALL"); - writeUleb128(os, WasmSym::applyTLSRelocs->getFunctionIndex(), + writeUleb128(os, ctx.sym.applyTLSRelocs->getFunctionIndex(), "function index"); } - if (WasmSym::applyGlobalTLSRelocs) { + if (ctx.sym.applyGlobalTLSRelocs) { writeU8(os, WASM_OPCODE_CALL, "CALL"); - writeUleb128(os, WasmSym::applyGlobalTLSRelocs->getFunctionIndex(), + writeUleb128(os, ctx.sym.applyGlobalTLSRelocs->getFunctionIndex(), "function index"); } writeU8(os, WASM_OPCODE_END, "end function"); } - createFunction(WasmSym::initTLS, bodyContent); + createFunction(ctx.sym.initTLS, bodyContent); } // Populate InitFunctions vector with init functions from all input objects. // This is then used either when creating the output linking section or to // synthesize the "__wasm_call_ctors" function. void Writer::calculateInitFunctions() { - if (!ctx.arg.relocatable && !WasmSym::callCtors->isLive()) + if (!ctx.arg.relocatable && !ctx.sym.callCtors->isLive()) return; for (ObjFile *file : ctx.objectFiles) { @@ -1715,8 +1712,8 @@ void Writer::createSyntheticSectionsPostLayout() { void Writer::run() { // For PIC code the table base is assigned dynamically by the loader. // For non-PIC, we start at 1 so that accessing table index 0 always traps. - if (!ctx.isPic && WasmSym::definedTableBase) - WasmSym::definedTableBase->setVA(ctx.arg.tableBase); + if (!ctx.isPic && ctx.sym.definedTableBase) + ctx.sym.definedTableBase->setVA(ctx.arg.tableBase); log("-- createOutputSegments"); createOutputSegments(); @@ -1784,14 +1781,18 @@ void Writer::run() { if (!ctx.arg.relocatable) { // Create linker synthesized functions - if (WasmSym::applyGlobalRelocs) + if (ctx.sym.applyGlobalRelocs) { createApplyGlobalRelocationsFunction(); - if (WasmSym::applyTLSRelocs) + } + if (ctx.sym.applyTLSRelocs) { createApplyTLSRelocationsFunction(); - if (WasmSym::applyGlobalTLSRelocs) + } + if (ctx.sym.applyGlobalTLSRelocs) { createApplyGlobalTLSRelocationsFunction(); - if (WasmSym::initMemory) + } + if (ctx.sym.initMemory) { createInitMemoryFunction(); + } createStartFunction(); createCallCtorsFunction(); @@ -1802,14 +1803,14 @@ void Writer::run() { // the input objects or an explicit export from the command-line, we // assume ctors and dtors are taken care of already. if (!ctx.arg.relocatable && !ctx.isPic && - !WasmSym::callCtors->isUsedInRegularObj && - !WasmSym::callCtors->isExported()) { + !ctx.sym.callCtors->isUsedInRegularObj && + !ctx.sym.callCtors->isExported()) { log("-- createCommandExportWrappers"); createCommandExportWrappers(); } } - if (WasmSym::initTLS && WasmSym::initTLS->isLive()) { + if (ctx.sym.initTLS && ctx.sym.initTLS->isLive()) { log("-- createInitTLSFunction"); createInitTLSFunction(); }