| ... | ... | @@ -29,10 +29,17 @@ comptime { |
| 29 | 29 | // function for the GD and LD models. This function is unlikely to actually be used, since the |
| 30 | 30 | // linker should be able to relax every TLS access to the LE model and therefore eliminate all |
| 31 | 31 | // calls to this function, but that isn't guaranteed. |
| 32 | | if (native_arch == .s390x) |
| 33 | | symbol(&__tls_get_offset, "__tls_get_offset") |
| 34 | | else |
| 32 | if (native_arch == .s390x) { |
| 33 | symbol(&__tls_get_offset, "__tls_get_offset"); |
| 34 | } else { |
| 35 | 35 | symbol(&__tls_get_addr, "__tls_get_addr"); |
| 36 | if (native_arch == .m68k) { |
| 37 | symbol(&__m68k_read_tp, "__m68k_read_tp"); |
| 38 | } |
| 39 | if (native_arch == .x86) { |
| 40 | symbol(&___tls_get_addr, "___tls_get_addr"); |
| 41 | } |
| 42 | } |
| 36 | 43 | } |
| 37 | 44 | |
| 38 | 45 | /// Represents an ELF TLS variant. |
| ... | ... | @@ -158,30 +165,12 @@ const current_dtv_offset = switch (native_arch) { |
| 158 | 165 | |
| 159 | 166 | /// Per-thread storage for the ELF TLS ABI. |
| 160 | 167 | const AbiTcb = switch (current_variant) { |
| 161 | | .I_original, .I_modified => switch (native_arch) { |
| 162 | | .aarch64, |
| 163 | | .aarch64_be, |
| 164 | | .alpha, |
| 165 | | .arm, |
| 166 | | .armeb, |
| 167 | | .hppa, |
| 168 | | .microblaze, |
| 169 | | .microblazeel, |
| 170 | | .sh, |
| 171 | | .sheb, |
| 172 | | .thumb, |
| 173 | | .thumbeb, |
| 174 | | .xtensa, |
| 175 | | .xtensaeb, |
| 176 | | => extern struct { |
| 177 | | /// This is offset by `current_dtv_offset`. |
| 178 | | dtv: usize, |
| 179 | | _reserved: ?*anyopaque, |
| 180 | | }, |
| 181 | | else => extern struct { |
| 182 | | /// This is offset by `current_dtv_offset`. |
| 183 | | dtv: usize, |
| 184 | | }, |
| 168 | .I_original => extern struct { |
| 169 | dtv: usize, |
| 170 | _reserved: ?*anyopaque, |
| 171 | }, |
| 172 | .I_modified => extern struct { |
| 173 | dtv: usize, |
| 185 | 174 | }, |
| 186 | 175 | .II => extern struct { |
| 187 | 176 | /// This is self-referential. |
| ... | ... | @@ -517,7 +506,7 @@ fn computeAreaDesc(phdrs: []elf.ElfN.Phdr) void { |
| 517 | 506 | var block_size: usize = undefined; |
| 518 | 507 | |
| 519 | 508 | if (tls_phdr) |phdr| { |
| 520 | | align_factor = phdr.@"align"; |
| 509 | align_factor = @max(phdr.@"align", 1); |
| 521 | 510 | |
| 522 | 511 | // The effective size in memory is represented by `memsz`; the length of the data stored |
| 523 | 512 | // in the `PT.TLS` segment is `filesz` and may be less than the former. |
| ... | ... | @@ -738,6 +727,12 @@ inline fn mmap(length: usize) usize { |
| 738 | 727 | } |
| 739 | 728 | } |
| 740 | 729 | |
| 730 | fn __m68k_read_tp() callconv(.c) ?*anyopaque { |
| 731 | comptime assert(native_arch == .m68k); |
| 732 | |
| 733 | return @ptrFromInt(getThreadPointer()); |
| 734 | } |
| 735 | |
| 741 | 736 | const TlsIndex = switch (native_arch) { |
| 742 | 737 | .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... |
| 743 | 738 | else => extern struct { module: usize, offset: usize }, // ...but not MIPS N32! |
| ... | ... | @@ -748,14 +743,26 @@ fn __tls_get_addr(ti: *const TlsIndex) callconv(.c) *anyopaque { |
| 748 | 743 | |
| 749 | 744 | assert(ti.module == 1); // The executable's module ID is always 1 |
| 750 | 745 | const tp = getThreadPointer(); |
| 751 | | const block: [*]u8 = switch (current_variant) { |
| 752 | | .I_original => @ptrFromInt(tp -% area_info.abi_tcb.offset +% area_info.block.offset), |
| 753 | | .I_modified => @ptrFromInt(tp -% current_tp_offset), |
| 746 | const block = switch (current_variant) { |
| 747 | .I_original => tp -% area_info.abi_tcb.offset +% area_info.block.offset, |
| 748 | .I_modified => tp -% current_tp_offset, |
| 754 | 749 | // The `.I_original` approach would also work for `.II`, but there is an |
| 755 | 750 | // alternative strategy which is one less operation: |
| 756 | | .II => @ptrFromInt(tp -% area_info.block.size), |
| 751 | .II => tp -% area_info.abi_tcb.offset, |
| 757 | 752 | }; |
| 758 | | return block[@intCast(ti.offset)..]; |
| 753 | return @ptrFromInt(block +% current_dtv_offset +% @as(usize, @intCast(ti.offset))); |
| 754 | } |
| 755 | |
| 756 | fn ___tls_get_addr() callconv(.naked) *anyopaque { |
| 757 | comptime assert(native_arch == .x86); |
| 758 | |
| 759 | // We receive the `TlsIndex` pointer in eax. |
| 760 | comptime assert(@sizeOf(AbiTcb) + @sizeOf(ZigTcb) + @offsetOf(Dtv, "tls_block") == 12); |
| 761 | asm volatile ( |
| 762 | \\ mov 4(%%eax), %%eax |
| 763 | \\ add %%gs:12, %%eax |
| 764 | \\ ret |
| 765 | ); |
| 759 | 766 | } |
| 760 | 767 | |
| 761 | 768 | fn __tls_get_offset() callconv(.naked) noreturn { |
| ... | ... | @@ -765,10 +772,10 @@ fn __tls_get_offset() callconv(.naked) noreturn { |
| 765 | 772 | asm volatile ( |
| 766 | 773 | \\ la %%r1, 0(%%r12, %%r2) |
| 767 | 774 | \\ lg %%r2, 8(%%r1) |
| 768 | | \\ lgrl %%r0, %[block_size] |
| 775 | \\ lgrl %%r0, %[abi_tcb_offset] |
| 769 | 776 | \\ sgr %%r2, %%r0 |
| 770 | 777 | \\ br %%r14 |
| 771 | 778 | : |
| 772 | | : [block_size] "s" (&area_info.block.size), |
| 779 | : [abi_tcb_offset] "s" (&area_info.abi_tcb.offset), |
| 773 | 780 | ); |
| 774 | 781 | } |