| ... | @@ -142,30 +142,14 @@ const current_dtv_offset = switch (native_arch) { | ... | @@ -142,30 +142,14 @@ const current_dtv_offset = switch (native_arch) { |
| 142 | | 142 | |
| 143 | /// Per-thread storage for the ELF TLS ABI. | 143 | /// Per-thread storage for the ELF TLS ABI. |
| 144 | const AbiTcb = switch (current_variant) { | 144 | const AbiTcb = switch (current_variant) { |
| 145 | .I_original, .I_modified => switch (native_arch) { | 145 | .I_original => extern struct { |
| 146 | .aarch64, | 146 | /// This is offset by `current_dtv_offset`. |
| 147 | .aarch64_be, | 147 | dtv: usize, |
| 148 | .alpha, | 148 | _reserved: ?*anyopaque, |
| 149 | .arm, | 149 | }, |
| 150 | .armeb, | 150 | .I_modified => extern struct { |
| 151 | .hppa, | 151 | /// This is offset by `current_dtv_offset`. |
| 152 | .microblaze, | 152 | dtv: usize, |
| 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 | }, | | |
| 169 | }, | 153 | }, |
| 170 | .II => extern struct { | 154 | .II => extern struct { |
| 171 | /// This is self-referential. | 155 | /// This is self-referential. |
| ... | @@ -500,7 +484,7 @@ fn computeAreaDesc(phdrs: []elf.ElfN.Phdr) void { | ... | @@ -500,7 +484,7 @@ fn computeAreaDesc(phdrs: []elf.ElfN.Phdr) void { |
| 500 | var block_size: usize = undefined; | 484 | var block_size: usize = undefined; |
| 501 | | 485 | |
| 502 | if (tls_phdr) |phdr| { | 486 | if (tls_phdr) |phdr| { |
| 503 | align_factor = phdr.@"align"; | 487 | align_factor = @max(phdr.@"align", 1); |
| 504 | | 488 | |
| 505 | // The effective size in memory is represented by `memsz`; the length of the data stored | 489 | // The effective size in memory is represented by `memsz`; the length of the data stored |
| 506 | // in the `PT.TLS` segment is `filesz` and may be less than the former. | 490 | // in the `PT.TLS` segment is `filesz` and may be less than the former. |
| ... | @@ -727,6 +711,11 @@ comptime { | ... | @@ -727,6 +711,11 @@ comptime { |
| 727 | // the linker should be able to relax every TLS access to the LE model and therefore | 711 | // the linker should be able to relax every TLS access to the LE model and therefore |
| 728 | // eliminate all calls to this function, but that isn't guaranteed. | 712 | // eliminate all calls to this function, but that isn't guaranteed. |
| 729 | const Fns = struct { | 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 | const TlsIndex = switch (native_arch) { | 719 | const TlsIndex = switch (native_arch) { |
| 731 | .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... | 720 | .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... |
| 732 | else => extern struct { module: usize, offset: usize }, // ...but not MIPS N32! | 721 | else => extern struct { module: usize, offset: usize }, // ...but not MIPS N32! |
| ... | @@ -736,14 +725,25 @@ comptime { | ... | @@ -736,14 +725,25 @@ comptime { |
| 736 | | 725 | |
| 737 | assert(ti.module == 1); // The executable's module ID is always 1 | 726 | assert(ti.module == 1); // The executable's module ID is always 1 |
| 738 | const tp = getThreadPointer(); | 727 | const tp = getThreadPointer(); |
| 739 | const block: [*]u8 = switch (current_variant) { | 728 | const block = switch (current_variant) { |
| 740 | .I_original => @ptrFromInt(tp -% area_desc.abi_tcb.offset +% area_desc.block.offset), | 729 | .I_original => tp -% area_desc.abi_tcb.offset +% area_desc.block.offset, |
| 741 | .I_modified => @ptrFromInt(tp -% current_tp_offset), | 730 | .I_modified => tp -% current_tp_offset, |
| 742 | // The `.I_original` approach would also work for `.II`, but there is an | 731 | // The `.I_original` approach would also work for `.II`, but there is an |
| 743 | // alternative strategy which is one less operation: | 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 | fn __tls_get_offset() callconv(.naked) noreturn { | 748 | fn __tls_get_offset() callconv(.naked) noreturn { |
| 749 | comptime assert(native_arch == .s390x); | 749 | comptime assert(native_arch == .s390x); |
| ... | @@ -752,18 +752,25 @@ comptime { | ... | @@ -752,18 +752,25 @@ comptime { |
| 752 | asm volatile ( | 752 | asm volatile ( |
| 753 | \\ la %%r1, 0(%%r12, %%r2) | 753 | \\ la %%r1, 0(%%r12, %%r2) |
| 754 | \\ lg %%r2, 8(%%r1) | 754 | \\ lg %%r2, 8(%%r1) |
| 755 | \\ lgrl %%r0, %[block_size] | 755 | \\ lgrl %%r0, %[abi_tcb_offset] |
| 756 | \\ sgr %%r2, %%r0 | 756 | \\ sgr %%r2, %%r0 |
| 757 | \\ br %%r14 | 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) | 764 | if (native_arch == .s390x) { |
| 765 | @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }) | 765 | @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }); |
| 766 | else | 766 | } else { |
| 767 | @export(&Fns.__tls_get_addr, .{ .name = "__tls_get_addr" }); | 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 | } |