[WebAssembly] Fix __init_tls_base global in coop threading (#208597)
This commit updates how `wasm-ld` initializes the `__init_tls_base` global during module instantiation. Previously this global was left entirely unmodified meaning that it was always 0. This change updates the `__wasm_init_memory` function to set this global dynamically in PIC mode based on the TLS address calculation, or in non-PIC mode the generation of `__wasm_init_memory` correctly sets it to the desired TLS address. cc https://github.com/WebAssembly/wasi-libc/issues/819
This commit is contained in:
1 parent
6c24753d2c
commit
13bd2f0ea2
3 files changed
+97
-8
No files matched your search
@@ -94,6 +94,28 @@ baz:
|
||||
# CHECK-NEXT: - Minimum: 0x2
|
||||
# CHECK-NOT: Shared
|
||||
|
||||
# Ensure __init_stack_pointer, __init_tls_base, and __tls_size are all correct.
|
||||
# CHECK: - Type: GLOBAL
|
||||
# CHECK-NEXT: Globals:
|
||||
# CHECK-NEXT: - Index: 0
|
||||
# CHECK-NEXT: Type: I32
|
||||
# CHECK-NEXT: Mutable: false
|
||||
# CHECK-NEXT: InitExpr:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 65536
|
||||
# CHECK-NEXT: - Index: 1
|
||||
# CHECK-NEXT: Type: I32
|
||||
# CHECK-NEXT: Mutable: true
|
||||
# CHECK-NEXT: InitExpr:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 65544
|
||||
# CHECK-NEXT: - Index: 2
|
||||
# CHECK-NEXT: Type: I32
|
||||
# CHECK-NEXT: Mutable: false
|
||||
# CHECK-NEXT: InitExpr:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 8
|
||||
|
||||
# The function table is exported by default.
|
||||
# CHECK: - Type: EXPORT
|
||||
# CHECK: - Name: __indirect_function_table
|
||||
@@ -137,8 +159,14 @@ baz:
|
||||
# CHECK-NEXT: Name: __tls_align
|
||||
|
||||
# DIS-LABEL: <__wasm_init_memory>:
|
||||
# DIS: memory.init 2, 0
|
||||
# DIS-NEXT: end
|
||||
# DIS-EMPTY:
|
||||
# DIS-NEXT: i32.const 65544
|
||||
# DIS-NEXT: i32.const 65544
|
||||
# DIS-NEXT: call 0
|
||||
# DIS-NEXT: i32.const 0
|
||||
# DIS-NEXT: i32.const 8
|
||||
# DIS-NEXT: memory.init 2, 0
|
||||
# DIS-NEXT: end
|
||||
|
||||
# DIS-LABEL: <_start>:
|
||||
# DIS-EMPTY:
|
||||
@@ -168,6 +196,35 @@ baz:
|
||||
# RUN: obj2yaml %t.so | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llvm-objdump --disassemble-symbols=__wasm_init_memory --no-show-raw-insn --no-leading-addr %t.so | FileCheck %s --check-prefix=PIC-DIS
|
||||
|
||||
# The stack pointer is imported under the libcall ABI name and
|
||||
# __wasm_set_tls_base is imported for TLS initialization.
|
||||
# PIC: - Type: IMPORT
|
||||
# PIC: Field: __init_stack_pointer
|
||||
# PIC-NEXT: Kind: GLOBAL
|
||||
# PIC-NEXT: GlobalType: I32
|
||||
# PIC-NEXT: GlobalMutable: false
|
||||
# PIC: Field: __memory_base
|
||||
# PIC: Field: __table_base
|
||||
# PIC: Field: __wasm_set_tls_base
|
||||
# PIC-NEXT: Kind: FUNCTION
|
||||
|
||||
# The PIC `__init_tls_base` global (global 3) is mutable and initialized ot
|
||||
# 0 since its final value is calculated once `__memory_base` is provided.
|
||||
# PIC: - Type: GLOBAL
|
||||
# PIC-NEXT: Globals:
|
||||
# PIC-NEXT: - Index: 3
|
||||
# PIC-NEXT: Type: I32
|
||||
# PIC-NEXT: Mutable: true
|
||||
# PIC-NEXT: InitExpr:
|
||||
# PIC-NEXT: Opcode: I32_CONST
|
||||
# PIC-NEXT: Value: 0
|
||||
# PIC-NEXT: - Index: 4
|
||||
# PIC-NEXT: Type: I32
|
||||
# PIC-NEXT: Mutable: false
|
||||
# PIC-NEXT: InitExpr:
|
||||
# PIC-NEXT: Opcode: I32_CONST
|
||||
# PIC-NEXT: Value: 8
|
||||
|
||||
# In PIC mode the active .rodata and .data segments are combined into a single
|
||||
# active segment at __memory_base; the TLS segment remains passive.
|
||||
# PIC: - Type: DATACOUNT
|
||||
@@ -185,15 +242,32 @@ baz:
|
||||
# PIC-NEXT: Content: '0100000002000000'
|
||||
# PIC-NEXT: - Type: CUSTOM
|
||||
|
||||
# PIC: GlobalNames:
|
||||
# PIC-NEXT: - Index: 0
|
||||
# PIC-NEXT: Name: __init_stack_pointer
|
||||
# PIC-NEXT: - Index: 1
|
||||
# PIC-NEXT: Name: __memory_base
|
||||
# PIC-NEXT: - Index: 2
|
||||
# PIC-NEXT: Name: __table_base
|
||||
# PIC-NEXT: - Index: 3
|
||||
# PIC-NEXT: Name: __init_tls_base
|
||||
# PIC-NEXT: - Index: 4
|
||||
# PIC-NEXT: Name: __tls_size
|
||||
# PIC-NEXT: - Index: 5
|
||||
# PIC-NEXT: Name: __tls_align
|
||||
|
||||
# Memory initialization in PIC mode has a few responsibilities: it calculates
|
||||
# the TLS address and puts it in a local, `__wasm_set_tls_base` is called,
|
||||
# TLS is initialized, and then finally BSS is zero'd out.
|
||||
# the TLS address and puts it in a local, stores it into the __init_tls_base
|
||||
# global, `__wasm_set_tls_base` is called, TLS is initialized, and then finally
|
||||
# BSS is zero'd out.
|
||||
# PIC-DIS: <__wasm_init_memory>:
|
||||
# PIC-DIS-NEXT: .local i32
|
||||
# PIC-DIS-NEXT: i32.const 8
|
||||
# PIC-DIS-NEXT: global.get {{[0-9]+}}
|
||||
# PIC-DIS-NEXT: global.get 1
|
||||
# PIC-DIS-NEXT: i32.add
|
||||
# PIC-DIS-NEXT: local.tee 0
|
||||
# PIC-DIS-NEXT: local.get 0
|
||||
# PIC-DIS-NEXT: global.set 3
|
||||
# PIC-DIS-NEXT: call {{[0-9]+}}
|
||||
# PIC-DIS-NEXT: local.get 0
|
||||
# PIC-DIS-NEXT: i32.const 0
|
||||
|
||||
+2
-3
@@ -981,9 +981,8 @@ static void createSyntheticSymbols() {
|
||||
// TLS symbols are all hidden/dso-local
|
||||
auto tls_base_name =
|
||||
ctx.arg.libcallThreadContext ? "__init_tls_base" : "__tls_base";
|
||||
ctx.sym.tlsBase =
|
||||
createGlobalVariable(tls_base_name, !ctx.arg.libcallThreadContext,
|
||||
WASM_SYMBOL_VISIBILITY_HIDDEN);
|
||||
ctx.sym.tlsBase = createGlobalVariable(tls_base_name, true,
|
||||
WASM_SYMBOL_VISIBILITY_HIDDEN);
|
||||
ctx.sym.tlsSize = createGlobalVariable("__tls_size", false,
|
||||
WASM_SYMBOL_VISIBILITY_HIDDEN);
|
||||
ctx.sym.tlsAlign = createGlobalVariable("__tls_align", false,
|
||||
|
||||
@@ -1416,13 +1416,29 @@ void Writer::createInitMemoryFunction() {
|
||||
// When we initialize the TLS segment we also set the TLS base.
|
||||
// This allows the runtime to use this static copy of the TLS data
|
||||
// for the first/main thread.
|
||||
//
|
||||
// Note that for `--cooperative-threading` this additionally configures
|
||||
// the `__init_tls_base` global which is the initial TLS value that can
|
||||
// be used for all new component model tasks. For non-PIC builds this
|
||||
// global's statically known value is now calculated, so it's updated
|
||||
// here. For PIC builds the result of the address computation above is
|
||||
// what's stored into the global.
|
||||
if (ctx.arg.isMultithreaded() && s->isTLS()) {
|
||||
if (ctx.isPic) {
|
||||
// Cache the result of the addition in the TLS address local
|
||||
writeU8(os, WASM_OPCODE_LOCAL_TEE, "local.tee");
|
||||
writeUleb128(os, tlsAddressLocal, "tls address local");
|
||||
if (ctx.arg.libcallThreadContext) {
|
||||
writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get");
|
||||
writeUleb128(os, tlsAddressLocal, "tls address local");
|
||||
writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set");
|
||||
writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(),
|
||||
"__init_tls_base");
|
||||
}
|
||||
} else {
|
||||
writePtrConst(os, s->startVA, is64, "destination address");
|
||||
if (ctx.arg.libcallThreadContext)
|
||||
ctx.sym.tlsBase->global->setPointerValue(s->startVA);
|
||||
}
|
||||
writeSetTLSBase(ctx, os);
|
||||
if (ctx.isPic) {
|
||||
|
||||
Reference in new issue
Block a user