| ... | @@ -29,10 +29,17 @@ comptime { | ... | @@ -29,10 +29,17 @@ comptime { |
| 29 | // function for the GD and LD models. This function is unlikely to actually be used, since the | 29 | // function for the GD and LD models. This function is unlikely to actually be used, since the |
| 30 | // linker should be able to relax every TLS access to the LE model and therefore eliminate all | 30 | // linker should be able to relax every TLS access to the LE model and therefore eliminate all |
| 31 | // calls to this function, but that isn't guaranteed. | 31 | // calls to this function, but that isn't guaranteed. |
| 32 | if (native_arch == .s390x) | 32 | if (native_arch == .s390x) { |
| 33 | symbol(&__tls_get_offset, "__tls_get_offset") | 33 | symbol(&__tls_get_offset, "__tls_get_offset"); |
| 34 | else | 34 | } else { |
| 35 | symbol(&__tls_get_addr, "__tls_get_addr"); | 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 | /// Represents an ELF TLS variant. | 45 | /// Represents an ELF TLS variant. |
| ... | @@ -158,30 +165,12 @@ const current_dtv_offset = switch (native_arch) { | ... | @@ -158,30 +165,12 @@ const current_dtv_offset = switch (native_arch) { |
| 158 | | 165 | |
| 159 | /// Per-thread storage for the ELF TLS ABI. | 166 | /// Per-thread storage for the ELF TLS ABI. |
| 160 | const AbiTcb = switch (current_variant) { | 167 | const AbiTcb = switch (current_variant) { |
| 161 | .I_original, .I_modified => switch (native_arch) { | 168 | .I_original => extern struct { |
| 162 | .aarch64, | 169 | dtv: usize, |
| 163 | .aarch64_be, | 170 | _reserved: ?*anyopaque, |
| 164 | .alpha, | 171 | }, |
| 165 | .arm, | 172 | .I_modified => extern struct { |
| 166 | .armeb, | 173 | dtv: usize, |
| 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 | }, | | |
| 185 | }, | 174 | }, |
| 186 | .II => extern struct { | 175 | .II => extern struct { |
| 187 | /// This is self-referential. | 176 | /// This is self-referential. |
| ... | @@ -517,7 +506,7 @@ fn computeAreaDesc(phdrs: []elf.ElfN.Phdr) void { | ... | @@ -517,7 +506,7 @@ fn computeAreaDesc(phdrs: []elf.ElfN.Phdr) void { |
| 517 | var block_size: usize = undefined; | 506 | var block_size: usize = undefined; |
| 518 | | 507 | |
| 519 | if (tls_phdr) |phdr| { | 508 | if (tls_phdr) |phdr| { |
| 520 | align_factor = phdr.@"align"; | 509 | align_factor = @max(phdr.@"align", 1); |
| 521 | | 510 | |
| 522 | // The effective size in memory is represented by `memsz`; the length of the data stored | 511 | // The effective size in memory is represented by `memsz`; the length of the data stored |
| 523 | // in the `PT.TLS` segment is `filesz` and may be less than the former. | 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,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 | const TlsIndex = switch (native_arch) { | 736 | const TlsIndex = switch (native_arch) { |
| 742 | .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... | 737 | .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... |
| 743 | else => extern struct { module: usize, offset: usize }, // ...but not MIPS N32! | 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,14 +743,26 @@ fn __tls_get_addr(ti: *const TlsIndex) callconv(.c) *anyopaque { |
| 748 | | 743 | |
| 749 | assert(ti.module == 1); // The executable's module ID is always 1 | 744 | assert(ti.module == 1); // The executable's module ID is always 1 |
| 750 | const tp = getThreadPointer(); | 745 | const tp = getThreadPointer(); |
| 751 | const block: [*]u8 = switch (current_variant) { | 746 | const block = switch (current_variant) { |
| 752 | .I_original => @ptrFromInt(tp -% area_info.abi_tcb.offset +% area_info.block.offset), | 747 | .I_original => tp -% area_info.abi_tcb.offset +% area_info.block.offset, |
| 753 | .I_modified => @ptrFromInt(tp -% current_tp_offset), | 748 | .I_modified => tp -% current_tp_offset, |
| 754 | // The `.I_original` approach would also work for `.II`, but there is an | 749 | // The `.I_original` approach would also work for `.II`, but there is an |
| 755 | // alternative strategy which is one less operation: | 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 | fn __tls_get_offset() callconv(.naked) noreturn { | 768 | fn __tls_get_offset() callconv(.naked) noreturn { |
| ... | @@ -765,10 +772,10 @@ fn __tls_get_offset() callconv(.naked) noreturn { | ... | @@ -765,10 +772,10 @@ fn __tls_get_offset() callconv(.naked) noreturn { |
| 765 | asm volatile ( | 772 | asm volatile ( |
| 766 | \\ la %%r1, 0(%%r12, %%r2) | 773 | \\ la %%r1, 0(%%r12, %%r2) |
| 767 | \\ lg %%r2, 8(%%r1) | 774 | \\ lg %%r2, 8(%%r1) |
| 768 | \\ lgrl %%r0, %[block_size] | 775 | \\ lgrl %%r0, %[abi_tcb_offset] |
| 769 | \\ sgr %%r2, %%r0 | 776 | \\ sgr %%r2, %%r0 |
| 770 | \\ br %%r14 | 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 | } |