diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll --- a/lld/test/wasm/data-segments.ll +++ b/lld/test/wasm/data-segments.ll @@ -178,6 +178,12 @@ ; DIS-NEXT: # 2: down to label0 ; DIS-NEXT: end +; NOPIC-DIS-NEXT: [[PTR]].const 1024 +; PIC-DIS-NEXT: [[PTR]].const 0 +; PIC-DIS-NEXT: global.get 1 +; PIC-DIS-NEXT: [[PTR]].add +; DIS-NEXT: call 1 + ; NOPIC-DIS-NEXT: [[PTR]].const 1028 ; PIC-DIS-NEXT: [[PTR]].const 4 ; PIC-DIS-NEXT: global.get 1 diff --git a/lld/test/wasm/tls-align.s b/lld/test/wasm/tls-align.s --- a/lld/test/wasm/tls-align.s +++ b/lld/test/wasm/tls-align.s @@ -73,7 +73,7 @@ # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Value: 1024 # __tls_size # CHECK-NEXT: - Index: 2 diff --git a/lld/test/wasm/tls.s b/lld/test/wasm/tls.s --- a/lld/test/wasm/tls.s +++ b/lld/test/wasm/tls.s @@ -106,7 +106,7 @@ # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Value: 1024 # __tls_size # CHECK-NEXT: - Index: 2 diff --git a/lld/test/wasm/tls_init_symbols.s b/lld/test/wasm/tls_init_symbols.s --- a/lld/test/wasm/tls_init_symbols.s +++ b/lld/test/wasm/tls_init_symbols.s @@ -42,8 +42,10 @@ # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Name: __wasm_init_tls # CHECK-NEXT: - Index: 2 -# CHECK-NEXT: Name: __wasm_apply_global_tls_relocs +# CHECK-NEXT: Name: __wasm_init_memory # CHECK-NEXT: - Index: 3 +# CHECK-NEXT: Name: __wasm_apply_global_tls_relocs +# CHECK-NEXT: - Index: 4 # CHECK-NEXT: Name: _start # DIS: <__wasm_init_tls>: @@ -53,7 +55,7 @@ # DIS-NEXT: i32.const 0 # DIS-NEXT: i32.const 4 # DIS-NEXT: memory.init 0, 0 -# DIS-NEXT: call 2 +# DIS-NEXT: call 3 # DIS-NEXT: end # DIS: <__wasm_apply_global_tls_relocs>: diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -652,6 +652,10 @@ make( is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); + // Called from __wasm_init_memory + WasmSym::initTLS->markLive(); + // Used by initTLS + WasmSym::tlsBase->markLive(); } } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -218,6 +218,7 @@ } static void setGlobalPtr(DefinedGlobal *g, uint64_t memoryPtr) { + LLVM_DEBUG(dbgs() << "setGlobalPtr " << g->getName() << " -> " << memoryPtr << "\n"); g->global->setPointerValue(memoryPtr); } @@ -276,13 +277,15 @@ memoryPtr, seg->size, seg->alignment)); if (!config->relocatable && seg->isTLS()) { - if (config->sharedMemory) { + if (WasmSym::tlsSize) { auto *tlsSize = cast(WasmSym::tlsSize); setGlobalPtr(tlsSize, seg->size); - + } + if (WasmSym::tlsAlign) { auto *tlsAlign = cast(WasmSym::tlsAlign); setGlobalPtr(tlsAlign, int64_t{1} << seg->alignment); - } else if (WasmSym::tlsBase) { + } + if (WasmSym::tlsBase) { auto *tlsBase = cast(WasmSym::tlsBase); setGlobalPtr(tlsBase, memoryPtr); } @@ -747,6 +750,7 @@ for (auto *f : toWrap) { auto funcNameStr = (f->getName() + ".command_export").str(); + LLVM_DEBUG(dbgs() << "export wrapper: " << funcNameStr << "\n"); commandExportWrapperNames.push_back(funcNameStr); const std::string &funcName = commandExportWrapperNames.back(); @@ -970,9 +974,6 @@ } bool Writer::needsPassiveInitialization(const OutputSegment *segment) { - // TLS segments are initialized separately - if (segment->isTLS()) - return false; // If bulk memory features is supported then we can perform bss initialization // (via memory.fill) during `__wasm_init_memory`. if (config->importMemory && !segment->requiredInBinary()) @@ -1010,8 +1011,6 @@ make(nullSignature, "__wasm_apply_global_tls_relocs")); WasmSym::applyGlobalTLSRelocs->markLive(); - // TLS relocations depend on the __tls_base symbols - WasmSym::tlsBase->markLive(); } if (config->isPic || @@ -1177,11 +1176,20 @@ if (config->isPic) { writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), - "memory_base"); + "__memory_base"); writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "i32.add"); } - if (s->isBss) { + + if (config->sharedMemory && s->isTLS()) { + // Call __wasm_init_tls, passing in the statically allocated TLS + // region. This means that the first thread to load a given module + // does not need to do any dynamic allocation or call + // __wasm_init_tls. + writeU8(os, WASM_OPCODE_CALL, "CALL"); + writeUleb128(os, WasmSym::initTLS->getFunctionIndex(), + "__wasm_init_tls function index"); + } else if (s->isBss) { writeI32Const(os, 0, "fill value"); writeI32Const(os, s->size, "memory region size"); writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); @@ -1243,6 +1251,11 @@ for (const OutputSegment *s : segments) { if (needsPassiveInitialization(s) && !s->isBss) { + // TODO(sbc): Remove this condition. Its only here to support + // legacy caller of __wasm_init_tls. + if (config->sharedMemory && s->isTLS()) { + continue; + } // data.drop instruction writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); writeUleb128(os, WASM_OPCODE_DATA_DROP, "data.drop"); @@ -1440,7 +1453,6 @@ writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "global index"); - WasmSym::tlsBase->markLive(); // FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend op. writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); @@ -1623,8 +1635,10 @@ } } - if (WasmSym::initTLS && WasmSym::initTLS->isLive()) + if (WasmSym::initTLS) { + log("-- createInitTLSFunction"); createInitTLSFunction(); + } if (errorCount()) return;