From 9daad52a12deaa0bc53f9a54cfad3e5c7ae907d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 22 Jul 2026 13:24:03 +0200 Subject: [PATCH] std.os.linux.tls: export __tls_get_offset instead of __tls_get_addr on s390x This needs to return the offset from TP for the variable, which will be negative because this is TLS variant II. This ABI does not use __tls_get_addr at all, so it's best not to even export it, as that will help catch bad code. --- lib/std/os/linux/tls.zig | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig index a42c44f29fe48de3383752055d7a63947ec52fd2..81ccd5cb56eb90ff1d2d9582f45c6b22630a5173 100644 --- a/lib/std/os/linux/tls.zig +++ b/lib/std/os/linux/tls.zig @@ -726,12 +726,14 @@ comptime { // function for the GD and LD models. This function is unlikely to actually be used, since // the linker should be able to relax every TLS access to the LE model and therefore // eliminate all calls to this function, but that isn't guaranteed. - _ = struct { + const Fns = struct { const TlsIndex = switch (native_arch) { .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... else => extern struct { module: usize, offset: usize }, // ...but not MIPS N32! }; - export fn __tls_get_addr(ti: *const TlsIndex) *anyopaque { + fn __tls_get_addr(ti: *const TlsIndex) callconv(.c) *anyopaque { + comptime assert(native_arch != .s390x); + assert(ti.module == 1); // The executable's module ID is always 1 const tp = getThreadPointer(); const block: [*]u8 = switch (current_variant) { @@ -743,6 +745,25 @@ comptime { }; return block[@intCast(ti.offset)..]; } + fn __tls_get_offset() callconv(.naked) noreturn { + comptime assert(native_arch == .s390x); + + // We receive the module's GOT pointer in r12 and the GOT offset in r2. + asm volatile ( + \\ la %%r1, 0(%%r12, %%r2) + \\ lg %%r2, 8(%%r1) + \\ lgrl %%r0, %[block_size] + \\ sgr %%r2, %%r0 + \\ br %%r14 + : + : [block_size] "s" (&area_desc.block.size), + ); + } }; + + if (native_arch == .s390x) + @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }) + else + @export(&Fns.__tls_get_addr, .{ .name = "__tls_get_addr" }); } } -- 2.54.0