| ... | ... | @@ -142,30 +142,14 @@ const current_dtv_offset = switch (native_arch) { |
| 142 | 142 | |
| 143 | 143 | /// Per-thread storage for the ELF TLS ABI. |
| 144 | 144 | const AbiTcb = switch (current_variant) { |
| 145 | | .I_original, .I_modified => switch (native_arch) { |
| 146 | | .aarch64, |
| 147 | | .aarch64_be, |
| 148 | | .alpha, |
| 149 | | .arm, |
| 150 | | .armeb, |
| 151 | | .hppa, |
| 152 | | .microblaze, |
| 153 | | .microblazeel, |
| 154 | | .sh, |
| 155 | | .sheb, |
| 156 | | .thumb, |
| 157 | | .thumbeb, |
| 158 | | .xtensa, |
| 159 | | .xtensaeb, |
| 160 | | => extern struct { |
| 161 | | /// This is offset by `current_dtv_offset`. |
| 162 | | dtv: usize, |
| 163 | | _reserved: ?*anyopaque, |
| 164 | | }, |
| 165 | | else => extern struct { |
| 166 | | /// This is offset by `current_dtv_offset`. |
| 167 | | dtv: usize, |
| 168 | | }, |
| 145 | .I_original => extern struct { |
| 146 | /// This is offset by `current_dtv_offset`. |
| 147 | dtv: usize, |
| 148 | _reserved: ?*anyopaque, |
| 149 | }, |
| 150 | .I_modified => extern struct { |
| 151 | /// This is offset by `current_dtv_offset`. |
| 152 | dtv: usize, |
| 169 | 153 | }, |
| 170 | 154 | .II => extern struct { |
| 171 | 155 | /// This is self-referential. |
| ... | ... | @@ -500,7 +484,7 @@ fn computeAreaDesc(phdrs: []elf.ElfN.Phdr) void { |
| 500 | 484 | var block_size: usize = undefined; |
| 501 | 485 | |
| 502 | 486 | if (tls_phdr) |phdr| { |
| 503 | | align_factor = phdr.@"align"; |
| 487 | align_factor = @max(phdr.@"align", 1); |
| 504 | 488 | |
| 505 | 489 | // The effective size in memory is represented by `memsz`; the length of the data stored |
| 506 | 490 | // in the `PT.TLS` segment is `filesz` and may be less than the former. |
| ... | ... | @@ -727,6 +711,11 @@ comptime { |
| 727 | 711 | // the linker should be able to relax every TLS access to the LE model and therefore |
| 728 | 712 | // eliminate all calls to this function, but that isn't guaranteed. |
| 729 | 713 | const Fns = struct { |
| 714 | fn __m68k_read_tp() callconv(.c) ?*anyopaque { |
| 715 | comptime assert(native_arch == .m68k); |
| 716 | |
| 717 | return @ptrFromInt(getThreadPointer()); |
| 718 | } |
| 730 | 719 | const TlsIndex = switch (native_arch) { |
| 731 | 720 | .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... |
| 732 | 721 | else => extern struct { module: usize, offset: usize }, // ...but not MIPS N32! |
| ... | ... | @@ -736,14 +725,25 @@ comptime { |
| 736 | 725 | |
| 737 | 726 | assert(ti.module == 1); // The executable's module ID is always 1 |
| 738 | 727 | const tp = getThreadPointer(); |
| 739 | | const block: [*]u8 = switch (current_variant) { |
| 740 | | .I_original => @ptrFromInt(tp -% area_desc.abi_tcb.offset +% area_desc.block.offset), |
| 741 | | .I_modified => @ptrFromInt(tp -% current_tp_offset), |
| 728 | const block = switch (current_variant) { |
| 729 | .I_original => tp -% area_desc.abi_tcb.offset +% area_desc.block.offset, |
| 730 | .I_modified => tp -% current_tp_offset, |
| 742 | 731 | // The `.I_original` approach would also work for `.II`, but there is an |
| 743 | 732 | // alternative strategy which is one less operation: |
| 744 | | .II => @ptrFromInt(tp -% area_desc.block.size), |
| 733 | .II => tp -% area_desc.abi_tcb.offset, |
| 745 | 734 | }; |
| 746 | | return block[@intCast(ti.offset)..]; |
| 735 | return @ptrFromInt(block +% current_dtv_offset +% @as(usize, @intCast(ti.offset))); |
| 736 | } |
| 737 | fn ___tls_get_addr() callconv(.naked) *anyopaque { |
| 738 | comptime assert(native_arch == .x86); |
| 739 | |
| 740 | // We receive the `TlsIndex` pointer in eax. |
| 741 | comptime assert(@sizeOf(AbiTcb) + @sizeOf(ZigTcb) + @offsetOf(Dtv, "tls_block") == 12); |
| 742 | asm volatile ( |
| 743 | \\ mov 4(%%eax), %%eax |
| 744 | \\ add %%gs:12, %%eax |
| 745 | \\ ret |
| 746 | ); |
| 747 | 747 | } |
| 748 | 748 | fn __tls_get_offset() callconv(.naked) noreturn { |
| 749 | 749 | comptime assert(native_arch == .s390x); |
| ... | ... | @@ -752,18 +752,25 @@ comptime { |
| 752 | 752 | asm volatile ( |
| 753 | 753 | \\ la %%r1, 0(%%r12, %%r2) |
| 754 | 754 | \\ lg %%r2, 8(%%r1) |
| 755 | | \\ lgrl %%r0, %[block_size] |
| 755 | \\ lgrl %%r0, %[abi_tcb_offset] |
| 756 | 756 | \\ sgr %%r2, %%r0 |
| 757 | 757 | \\ br %%r14 |
| 758 | 758 | : |
| 759 | | : [block_size] "s" (&area_desc.block.size), |
| 759 | : [abi_tcb_offset] "s" (&area_desc.abi_tcb.offset), |
| 760 | 760 | ); |
| 761 | 761 | } |
| 762 | 762 | }; |
| 763 | 763 | |
| 764 | | if (native_arch == .s390x) |
| 765 | | @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }) |
| 766 | | else |
| 764 | if (native_arch == .s390x) { |
| 765 | @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }); |
| 766 | } else { |
| 767 | 767 | @export(&Fns.__tls_get_addr, .{ .name = "__tls_get_addr" }); |
| 768 | if (native_arch == .m68k) { |
| 769 | @export(&Fns.__m68k_read_tp, .{ .name = "__m68k_read_tp" }); |
| 770 | 	 } |
| 771 | 	 if (native_arch == .x86) { |
| 772 | @export(&Fns.___tls_get_addr, .{ .name = "___tls_get_addr" }); |
| 773 | 	 } |
| 774 | } |
| 768 | 775 | } |
| 769 | 776 | } |