From a11c20e26a6efd977656459710ae3d37fcbb2846 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 21 Sep 2019 23:10:45 +0200 Subject: [PATCH] Fix TLS for VariantI arches with a twist --- std/os/linux/tls.zig | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/std/os/linux/tls.zig b/std/os/linux/tls.zig index 8b9846b10f..4186067f89 100644 --- a/std/os/linux/tls.zig +++ b/std/os/linux/tls.zig @@ -47,7 +47,7 @@ const TLSVariant = enum { }; const tls_variant = switch (builtin.arch) { - .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64 => TLSVariant.VariantI, + .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mipsel => TLSVariant.VariantI, .x86_64, .i386 => TLSVariant.VariantII, else => @compileError("undefined tls_variant for this architecture"), }; @@ -57,8 +57,7 @@ const tls_tcb_size = switch (builtin.arch) { // ARM EABI mandates enough space for two pointers: the first one points to // the DTV while the second one is unspecified but reserved .arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize), - .i386, .x86_64 => @sizeOf(usize), - else => 0, + else => @sizeOf(usize), }; // Controls if the TCB should be aligned according to the TLS segment p_align @@ -67,6 +66,12 @@ const tls_tcb_align_size = switch (builtin.arch) { else => false, }; +// Controls if the TP points to the end of the TCB instead of its beginning +const tls_tp_points_past_tcb = switch (builtin.arch) { + .riscv32, .riscv64, .mipsel, .powerpc64, .powerpc64le => true, + else => false, +}; + // Check if the architecture-specific parameters look correct comptime { if (tls_tcb_align_size and tls_variant != TLSVariant.VariantI) { @@ -78,10 +83,12 @@ comptime { // make the generated code more efficient const tls_tp_offset = switch (builtin.arch) { + .mipsel => 0x7000, else => 0, }; const tls_dtv_offset = switch (builtin.arch) { + .mipsel => 0x8000, else => 0, }; @@ -119,7 +126,8 @@ pub fn setThreadPointer(addr: usize) void { ); }, .arm => |arm| { - _ = std.os.linux.syscall1(std.os.linux.SYS_set_tls, addr); + const rc = std.os.linux.syscall1(std.os.linux.SYS_set_tls, addr); + assert(rc == 0); }, .riscv64 => { asm volatile ( @@ -251,7 +259,8 @@ pub fn copyTLS(addr: usize) usize { @memcpy(@intToPtr([*]u8, addr + tls_img.data_offset), tls_img.data_src.ptr, tls_img.data_src.len); // Return the corrected (if needed) value for the tp register - return addr + tls_img.tcb_offset + tls_tp_offset; + return addr + tls_tp_offset + + if (tls_tp_points_past_tcb) tls_img.data_offset else tls_img.tcb_offset; } var main_thread_tls_buffer: [256]u8 align(32) = undefined;