Commit e4d595a8ba

Andrew Kelley <andrew@ziglang.org>
2019-04-04 07:08:26
fix thread local variables for non- position independent code
This fixes comes thanks to Rich Felker from the musl libc project, who gave me this crucial information: "to satisfy the abi, your init code has to write the same value to that memory location as the value passed to the [arch_prctl] syscall" This commit also changes the rules for when to build statically by default. When building objects and static libraries, position independent code is disabled if no libraries will be dynamically linked and the target does not require position independent code. closes #2063
1 parent 70ae322
Changed files (6)
src
std
test
stage1
behavior
src/codegen.cpp
@@ -7314,17 +7314,14 @@ static bool detect_dynamic_link(CodeGen *g) {
         return false;
     if (target_requires_pic(g->zig_target, g->libc_link_lib != nullptr))
         return true;
-    if (g->out_type == OutTypeExe) {
-        // If there are no dynamic libraries then we can disable PIC
-        for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
-            LinkLib *link_lib = g->link_libs_list.at(i);
-            if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name)))
-                continue;
-            return true;
-        }
-        return false;
+    // If there are no dynamic libraries then we can disable PIC
+    for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
+        LinkLib *link_lib = g->link_libs_list.at(i);
+        if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name)))
+            continue;
+        return true;
     }
-    return true;
+    return false;
 }
 
 static bool detect_pic(CodeGen *g) {
src/main.cpp
@@ -938,11 +938,6 @@ int main(int argc, char **argv) {
         return print_error_usage(arg0);
     }
 
-    if (out_type != OutTypeLib && is_dynamic) {
-        fprintf(stderr, "`-dynamic` may only be specified with `build-lib`.\n");
-        return print_error_usage(arg0);
-    }
-
     if (llvm_argv.length > 1) {
         llvm_argv.append(nullptr);
         ZigLLVMParseCommandLineOptions(llvm_argv.length - 1, llvm_argv.items);
std/os/test.zig
@@ -108,10 +108,6 @@ test "AtomicFile" {
 
 test "thread local storage" {
     if (builtin.single_threaded) return error.SkipZigTest;
-    if (!builtin.position_independent_code and !builtin.link_libc) {
-        // TODO https://github.com/ziglang/zig/issues/2063
-        return error.SkipZigTest;
-    }
     const thread1 = try std.os.spawnThread({}, testTls);
     const thread2 = try std.os.spawnThread({}, testTls);
     testTls({});
std/special/bootstrap.zig
@@ -134,7 +134,6 @@ inline fn callMain() u8 {
     }
 }
 
-var tls_end_addr: usize = undefined;
 const main_thread_tls_align = 32;
 var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64;
 
@@ -156,11 +155,14 @@ fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent:
     }
     const tls_phdr = std.os.linux_tls_phdr orelse return;
     std.os.linux_tls_img_src = @intToPtr([*]const u8, base + tls_phdr.p_vaddr);
-    assert(main_thread_tls_bytes.len >= tls_phdr.p_memsz); // not enough preallocated Thread Local Storage
+    const end_addr = @ptrToInt(&main_thread_tls_bytes) + tls_phdr.p_memsz;
+    const max_end_addr = @ptrToInt(&main_thread_tls_bytes) + main_thread_tls_bytes.len;
+    assert(max_end_addr >= end_addr + @sizeOf(usize)); // not enough preallocated Thread Local Storage
     assert(main_thread_tls_align >= tls_phdr.p_align); // preallocated Thread Local Storage not aligned enough
     @memcpy(&main_thread_tls_bytes, std.os.linux_tls_img_src, tls_phdr.p_filesz);
-    tls_end_addr = @ptrToInt(&main_thread_tls_bytes) + tls_phdr.p_memsz;
-    linuxSetThreadArea(@ptrToInt(&tls_end_addr));
+    const end_ptr = @intToPtr(*usize, end_addr);
+    end_ptr.* = end_addr;
+    linuxSetThreadArea(end_addr);
 }
 
 fn linuxSetThreadArea(addr: usize) void {
std/os.zig
@@ -2934,7 +2934,6 @@ pub const Thread = struct {
             handle: Thread.Handle,
             mmap_addr: usize,
             mmap_len: usize,
-            tls_end_addr: usize,
         },
         builtin.Os.windows => struct {
             handle: Thread.Handle,
@@ -3185,8 +3184,8 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
         var newtls: usize = undefined;
         if (linux_tls_phdr) |tls_phdr| {
             @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), linux_tls_img_src, tls_phdr.p_filesz);
-            thread_ptr.data.tls_end_addr = mmap_addr + mmap_len;
-            newtls = @ptrToInt(&thread_ptr.data.tls_end_addr);
+            newtls = mmap_addr + mmap_len;
+            @intToPtr(*usize, newtls).* = newtls;
             flags |= posix.CLONE_SETTLS;
         }
         const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
test/stage1/behavior/misc.zig
@@ -688,11 +688,6 @@ fn getNull() ?*i32 {
 }
 
 test "thread local variable" {
-    if (!builtin.position_independent_code and !builtin.link_libc) {
-        // TODO https://github.com/ziglang/zig/issues/2063
-        return error.SkipZigTest;
-    }
-
     const S = struct {
         threadlocal var t: i32 = 1234;
     };