Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lld/test/wasm/pic-static.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 37 additions & 0 deletions lld/test/wasm/tls-base-non-shared-memory.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Test that linking without shared memory causes __tls_base to be
Comment thread
sbc100 marked this conversation as resolved.
# 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
15 changes: 11 additions & 4 deletions lld/wasm/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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") &&
Expand All @@ -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);
Expand Down