Commit a11c20e26a

LemonBoy <thatlemon@gmail.com>
2019-09-21 23:10:45
Fix TLS for VariantI arches with a twist
1 parent 4dd17a7
Changed files (1)
std
os
linux
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;