| ... | ... | @@ -726,12 +726,14 @@ comptime { |
| 726 | 726 | // function for the GD and LD models. This function is unlikely to actually be used, since |
| 727 | 727 | // the linker should be able to relax every TLS access to the LE model and therefore |
| 728 | 728 | // eliminate all calls to this function, but that isn't guaranteed. |
| 729 | | _ = struct { |
| 729 | const Fns = struct { |
| 730 | 730 | const TlsIndex = switch (native_arch) { |
| 731 | 731 | .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... |
| 732 | 732 | else => extern struct { module: usize, offset: usize }, // ...but not MIPS N32! |
| 733 | 733 | }; |
| 734 | | export fn __tls_get_addr(ti: *const TlsIndex) *anyopaque { |
| 734 | fn __tls_get_addr(ti: *const TlsIndex) callconv(.c) *anyopaque { |
| 735 | comptime assert(native_arch != .s390x); |
| 736 | |
| 735 | 737 | assert(ti.module == 1); // The executable's module ID is always 1 |
| 736 | 738 | const tp = getThreadPointer(); |
| 737 | 739 | const block: [*]u8 = switch (current_variant) { |
| ... | ... | @@ -743,6 +745,25 @@ comptime { |
| 743 | 745 | }; |
| 744 | 746 | return block[@intCast(ti.offset)..]; |
| 745 | 747 | } |
| 748 | fn __tls_get_offset() callconv(.naked) noreturn { |
| 749 | comptime assert(native_arch == .s390x); |
| 750 | |
| 751 | // We receive the module's GOT pointer in r12 and the GOT offset in r2. |
| 752 | asm volatile ( |
| 753 | \\ la %%r1, 0(%%r12, %%r2) |
| 754 | \\ lg %%r2, 8(%%r1) |
| 755 | \\ lgrl %%r0, %[block_size] |
| 756 | \\ sgr %%r2, %%r0 |
| 757 | \\ br %%r14 |
| 758 | : |
| 759 | : [block_size] "s" (&area_desc.block.size), |
| 760 | ); |
| 761 | } |
| 746 | 762 | }; |
| 763 | |
| 764 | if (native_arch == .s390x) |
| 765 | @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }) |
| 766 | else |
| 767 | @export(&Fns.__tls_get_addr, .{ .name = "__tls_get_addr" }); |
| 747 | 768 | } |
| 748 | 769 | } |