[lld][WebAssembly] Always initialize fixed __tls_base in single threaded mode (#193563)
Without this fix `__tls_base` can remain set to zero which leads `__builtin_thread_pointer` to return NULL, which is should not. See https://github.com/emscripten-core/emscripten/pull/26747
This commit is contained in:
@@ -124,7 +124,7 @@ ret32_ptr:
|
||||
# CHECK-NEXT: Mutable: false
|
||||
# CHECK-NEXT: InitExpr:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 0
|
||||
# CHECK-NEXT: Value: 65536
|
||||
|
||||
# GOT.func.internal.ret32
|
||||
# CHECK-NEXT: - Index: 4
|
||||
|
||||
37
lld/test/wasm/tls-base-non-shared-memory.s
Normal file
37
lld/test/wasm/tls-base-non-shared-memory.s
Normal file
@@ -0,0 +1,37 @@
|
||||
# Test that linking without shared memory causes __tls_base to be
|
||||
# internalized, and initialized to a non-zero value, even without any TLS data
|
||||
# present.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
|
||||
# RUN: wasm-ld -o %t.wasm %t.o
|
||||
# RUN: obj2yaml %t.wasm | FileCheck %s
|
||||
|
||||
.globaltype __tls_base, i32
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
.functype _start () -> ()
|
||||
global.get __tls_base
|
||||
drop
|
||||
end_function
|
||||
|
||||
# CHECK: - Type: GLOBAL
|
||||
# CHECK-NEXT: Globals:
|
||||
# CHECK-NEXT: - Index: 0
|
||||
# CHECK-NEXT: Type: I32
|
||||
# CHECK-NEXT: Mutable: true
|
||||
# CHECK-NEXT: InitExpr:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 65536
|
||||
# CHECK-NEXT: - Index: 1
|
||||
# CHECK-NEXT: Type: I32
|
||||
# CHECK-NEXT: Mutable: false
|
||||
# CHECK-NEXT: InitExpr:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 65536
|
||||
|
||||
# CHECK: GlobalNames:
|
||||
# CHECK-NEXT: - Index: 0
|
||||
# CHECK-NEXT: Name: __stack_pointer
|
||||
# CHECK-NEXT: - Index: 1
|
||||
# CHECK-NEXT: Name: __tls_base
|
||||
@@ -381,6 +381,7 @@ void Writer::layoutMemory() {
|
||||
ctx.sym.dsoHandle->setVA(dataStart);
|
||||
|
||||
out.dylinkSec->memAlign = 0;
|
||||
uint64_t fixedTLSBase = memoryPtr;
|
||||
for (OutputSegment *seg : segments) {
|
||||
out.dylinkSec->memAlign = std::max(out.dylinkSec->memAlign, seg->alignment);
|
||||
memoryPtr = alignTo(memoryPtr, 1ULL << seg->alignment);
|
||||
@@ -397,10 +398,7 @@ void Writer::layoutMemory() {
|
||||
auto *tlsAlign = cast<DefinedGlobal>(ctx.sym.tlsAlign);
|
||||
setGlobalPtr(tlsAlign, int64_t{1} << seg->alignment);
|
||||
}
|
||||
if (!ctx.arg.sharedMemory && ctx.sym.tlsBase) {
|
||||
auto *tlsBase = cast<DefinedGlobal>(ctx.sym.tlsBase);
|
||||
setGlobalPtr(tlsBase, memoryPtr);
|
||||
}
|
||||
fixedTLSBase = memoryPtr;
|
||||
}
|
||||
|
||||
if (ctx.sym.rodataStart && seg->name.starts_with(".rodata") &&
|
||||
@@ -414,6 +412,15 @@ void Writer::layoutMemory() {
|
||||
ctx.sym.rodataEnd->setVA(memoryPtr);
|
||||
}
|
||||
|
||||
// In single-threaded builds we set __tls_base statically.
|
||||
// Even in the absense of any actual TLS data, this symbol can still be
|
||||
// referenced (for example by __builtin_thread_pointer, which should not
|
||||
// return NULL).
|
||||
if (!ctx.arg.sharedMemory && ctx.sym.tlsBase) {
|
||||
auto *tlsBase = cast<DefinedGlobal>(ctx.sym.tlsBase);
|
||||
setGlobalPtr(tlsBase, fixedTLSBase);
|
||||
}
|
||||
|
||||
// Make space for the memory initialization flag
|
||||
if (ctx.arg.sharedMemory && hasPassiveInitializedSegments()) {
|
||||
memoryPtr = alignTo(memoryPtr, 4);
|
||||
|
||||
Reference in New Issue
Block a user