From 04624c10801cd9d10971a634f3b25db3d3def87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Oct 2026 10:43:26 +0200 Subject: [PATCH] std.os.linux.tls: manual backport of https://codeberg.org/ziglang/zig/pulls/37186 --- lib/std/os/linux/tls.zig | 77 ++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig index aed76fc0cb2ee83318e5c0e2d72b0016cf44eb91..a804115344259e58e5300c8c30868f3548aff487 100644 --- a/lib/std/os/linux/tls.zig +++ b/lib/std/os/linux/tls.zig @@ -142,30 +142,14 @@ const current_dtv_offset = switch (native_arch) { /// Per-thread storage for the ELF TLS ABI. const AbiTcb = switch (current_variant) { - .I_original, .I_modified => switch (native_arch) { - .aarch64, - .aarch64_be, - .alpha, - .arm, - .armeb, - .hppa, - .microblaze, - .microblazeel, - .sh, - .sheb, - .thumb, - .thumbeb, - .xtensa, - .xtensaeb, - => extern struct { - /// This is offset by `current_dtv_offset`. - dtv: usize, - _reserved: ?*anyopaque, - }, - else => extern struct { - /// This is offset by `current_dtv_offset`. - dtv: usize, - }, + .I_original => extern struct { + /// This is offset by `current_dtv_offset`. + dtv: usize, + _reserved: ?*anyopaque, + }, + .I_modified => extern struct { + /// This is offset by `current_dtv_offset`. + dtv: usize, }, .II => extern struct { /// This is self-referential. @@ -500,7 +484,7 @@ fn computeAreaDesc(phdrs: []elf.ElfN.Phdr) void { var block_size: usize = undefined; if (tls_phdr) |phdr| { - align_factor = phdr.@"align"; + align_factor = @max(phdr.@"align", 1); // The effective size in memory is represented by `memsz`; the length of the data stored // in the `PT.TLS` segment is `filesz` and may be less than the former. @@ -727,6 +711,11 @@ comptime { // 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. const Fns = struct { + fn __m68k_read_tp() callconv(.c) ?*anyopaque { + comptime assert(native_arch == .m68k); + + return @ptrFromInt(getThreadPointer()); + } 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! @@ -736,14 +725,25 @@ comptime { assert(ti.module == 1); // The executable's module ID is always 1 const tp = getThreadPointer(); - const block: [*]u8 = switch (current_variant) { - .I_original => @ptrFromInt(tp -% area_desc.abi_tcb.offset +% area_desc.block.offset), - .I_modified => @ptrFromInt(tp -% current_tp_offset), + const block = switch (current_variant) { + .I_original => tp -% area_desc.abi_tcb.offset +% area_desc.block.offset, + .I_modified => tp -% current_tp_offset, // The `.I_original` approach would also work for `.II`, but there is an // alternative strategy which is one less operation: - .II => @ptrFromInt(tp -% area_desc.block.size), + .II => tp -% area_desc.abi_tcb.offset, }; - return block[@intCast(ti.offset)..]; + return @ptrFromInt(block +% current_dtv_offset +% @as(usize, @intCast(ti.offset))); + } + fn ___tls_get_addr() callconv(.naked) *anyopaque { + comptime assert(native_arch == .x86); + + // We receive the `TlsIndex` pointer in eax. + comptime assert(@sizeOf(AbiTcb) + @sizeOf(ZigTcb) + @offsetOf(Dtv, "tls_block") == 12); + asm volatile ( + \\ mov 4(%%eax), %%eax + \\ add %%gs:12, %%eax + \\ ret + ); } fn __tls_get_offset() callconv(.naked) noreturn { comptime assert(native_arch == .s390x); @@ -752,18 +752,25 @@ comptime { asm volatile ( \\ la %%r1, 0(%%r12, %%r2) \\ lg %%r2, 8(%%r1) - \\ lgrl %%r0, %[block_size] + \\ lgrl %%r0, %[abi_tcb_offset] \\ sgr %%r2, %%r0 \\ br %%r14 : - : [block_size] "s" (&area_desc.block.size), + : [abi_tcb_offset] "s" (&area_desc.abi_tcb.offset), ); } }; - if (native_arch == .s390x) - @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }) - else + if (native_arch == .s390x) { + @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }); + } else { @export(&Fns.__tls_get_addr, .{ .name = "__tls_get_addr" }); + if (native_arch == .m68k) { + @export(&Fns.__m68k_read_tp, .{ .name = "__m68k_read_tp" }); + } + if (native_arch == .x86) { + @export(&Fns.___tls_get_addr, .{ .name = "___tls_get_addr" }); + } + } } } -- 2.54.0