| author | |
| committer | |
| log | 292edd2440baa02864f1d2fe2dc08140d0c3c7a6 |
| tree | a814259b8231019ef01c9dd1cf7757d07755a873 |
| parent | 65b3cb2db988f7cf67fe5c2f39c96824e9497e3e |
| signature | Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM |
This gets rid of the super confusing and (as far as I can tell) incorrect
getauxval logic in std.os.linux, and clarifies exactly who owns this state.
The ABI that std now expects is:
extern var __zig_elf_auxv: [*]std.elf.Auxv;
Users can technically override this weak symbol with a strong symbol if they
wish, although I see no particularly useful reason to do so.
It is now a compile error to use std.os.linux.getauxval if libc is linked,
whereas previously it would just give useless results in some cases. I consider
this to be strictly an improvement. Just use std.c.getauxval when linking libc,
which std already does correctly where it needs getauxval.
This code is expected to be further simplified once our baseline Linux version
allows implementing https://codeberg.org/ziglang/zig/issues/31290.
closes https://codeberg.org/ziglang/zig/issues/362036 files changed, 47 insertions(+), 37 deletions(-)
lib/compiler_rt.zig+2| ... | ... | @@ -164,6 +164,8 @@ comptime { |
| 164 | 164 | symbol(&strlen, "strlen"); |
| 165 | 165 | } |
| 166 | 166 | |
| 167 | _ = @import("compiler_rt/elf.zig"); | |
| 168 | ||
| 167 | 169 | // Temporarily used for uefi until https://github.com/ziglang/zig/issues/21630 is addressed. |
| 168 | 170 | if (!builtin.link_libc and (builtin.os.tag == .windows or builtin.os.tag == .uefi) and (builtin.abi == .none or builtin.abi == .msvc)) { |
| 169 | 171 | symbol(&_fltused, "_fltused"); |
lib/compiler_rt/elf.zig created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | comptime { | |
| 2 | _ = @import("elf/auxv.zig"); | |
| 3 | } |
lib/compiler_rt/elf/auxv.zig created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | ||
| 4 | const compiler_rt = @import("../../compiler_rt.zig"); | |
| 5 | const symbol = compiler_rt.symbol; | |
| 6 | ||
| 7 | comptime { | |
| 8 | // FreeBSD, NetBSD, and OpenBSD are expected to also use this in the future. | |
| 9 | if (!builtin.link_libc and builtin.target.os.tag == .linux) { | |
| 10 | symbol(@ptrCast(&__zig_elf_auxv), "__zig_elf_auxv"); | |
| 11 | } | |
| 12 | } | |
| 13 | ||
| 14 | /// Populated by `std.start` when libc is not linked on targets that provide an ELF auxiliary vector | |
| 15 | /// to the process on startup. Provided by compiler-rt so that there is no confusion about where | |
| 16 | /// this state lives regardless of how the final artifact (executable or shared library) is | |
| 17 | /// compiled. | |
| 18 | /// | |
| 19 | /// It is expected that this will gradually be replaced with better mechanisms as operating systems | |
| 20 | /// improve; see https://codeberg.org/ziglang/zig/issues/31290. | |
| 21 | var __zig_elf_auxv: [*]std.elf.Auxv = undefined; |
lib/std/os/linux.zig+14-35| ... | ... | @@ -960,43 +960,22 @@ pub const RENAME = packed struct(u32) { |
| 960 | 960 | _: u29 = 0, |
| 961 | 961 | }; |
| 962 | 962 | |
| 963 | /// Set by startup code, used by `getauxval`. | |
| 964 | pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; | |
| 965 | ||
| 966 | /// Whether an external or internal getauxval implementation is used. | |
| 967 | const extern_getauxval = switch (builtin.zig_backend) { | |
| 968 | // Calling extern functions is not yet supported with these backends | |
| 969 | .stage2_arm, | |
| 970 | .stage2_loongarch, | |
| 971 | .stage2_powerpc, | |
| 972 | .stage2_riscv64, | |
| 973 | .stage2_sparc64, | |
| 974 | => false, | |
| 975 | else => !builtin.link_libc, | |
| 976 | }; | |
| 977 | ||
| 978 | pub const getauxval = if (extern_getauxval) struct { | |
| 979 | comptime { | |
| 980 | const root = @import("root"); | |
| 981 | // Export this only when building an executable, otherwise it is overriding | |
| 982 | // the libc implementation | |
| 983 | if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { | |
| 984 | @export(&getauxvalImpl, .{ .name = "getauxval", .linkage = .weak }); | |
| 963 | /// Available only when libc is *not* linked; use `std.c.getauxval` if libc is linked. | |
| 964 | pub const getauxval = if (builtin.link_libc) {} else struct { | |
| 965 | /// Provided by compiler-rt and set by `std.start`. | |
| 966 | extern var __zig_elf_auxv: [*]std.elf.Auxv; | |
| 967 | ||
| 968 | pub fn getauxval(index: usize) usize { | |
| 969 | @disableInstrumentation(); | |
| 970 | ||
| 971 | var i: usize = 0; | |
| 972 | while (__zig_elf_auxv[i].a_type != std.elf.AT.NULL) : (i += 1) { | |
| 973 | if (__zig_elf_auxv[i].a_type == index) return __zig_elf_auxv[i].a_un.a_val; | |
| 985 | 974 | } |
| 975 | ||
| 976 | return 0; | |
| 986 | 977 | } |
| 987 | extern fn getauxval(index: usize) usize; | |
| 988 | }.getauxval else getauxvalImpl; | |
| 989 | ||
| 990 | fn getauxvalImpl(index: usize) callconv(.c) usize { | |
| 991 | @disableInstrumentation(); | |
| 992 | const auxv = elf_aux_maybe orelse return 0; | |
| 993 | var i: usize = 0; | |
| 994 | while (auxv[i].a_type != std.elf.AT.NULL) : (i += 1) { | |
| 995 | if (auxv[i].a_type == index) | |
| 996 | return auxv[i].a_un.a_val; | |
| 997 | } | |
| 998 | return 0; | |
| 999 | } | |
| 978 | }.getauxval; | |
| 1000 | 979 | |
| 1001 | 980 | // Some architectures (and some syscalls) require 64bit parameters to be passed |
| 1002 | 981 | // in a even-aligned register pair. |
lib/std/os/linux/vdso.zig+3-1| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | 2 | const std = @import("../../std.zig"); |
| 2 | 3 | const elf = std.elf; |
| 3 | 4 | const linux = std.os.linux; |
| ... | ... | @@ -5,7 +6,8 @@ const mem = std.mem; |
| 5 | 6 | const maxInt = std.math.maxInt; |
| 6 | 7 | |
| 7 | 8 | pub fn lookup(vername: []const u8, name: []const u8) usize { |
| 8 | const vdso_addr = linux.getauxval(std.elf.AT.SYSINFO_EHDR); | |
| 9 | const getauxval = if (builtin.link_libc) std.c.getauxval else linux.getauxval; | |
| 10 | const vdso_addr = getauxval(std.elf.AT.SYSINFO_EHDR); | |
| 9 | 11 | if (vdso_addr == 0) return 0; |
| 10 | 12 | |
| 11 | 13 | const eh = @as(*elf.Ehdr, @ptrFromInt(vdso_addr)); |
lib/std/start.zig+4-1| ... | ... | @@ -596,6 +596,9 @@ fn wWinMain(hInstance: *anyopaque, hPrevInstance: ?*anyopaque, pCmdLine: [*:0]u1 |
| 596 | 596 | return root.wWinMain(@ptrCast(hInstance), @ptrCast(hPrevInstance), pCmdLine, @intCast(nCmdShow)); |
| 597 | 597 | } |
| 598 | 598 | |
| 599 | /// Provided by compiler-rt. | |
| 600 | extern var __zig_elf_auxv: [*]std.elf.Auxv; | |
| 601 | ||
| 599 | 602 | fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { |
| 600 | 603 | // We're not ready to panic until thread local storage is initialized. |
| 601 | 604 | @setRuntimeSafety(false); |
| ... | ... | @@ -638,7 +641,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { |
| 638 | 641 | if (native_os == .linux) { |
| 639 | 642 | // This must be done after PIE relocations have been applied or we may crash |
| 640 | 643 | // while trying to access the global variable (happens on MIPS at least). |
| 641 | std.os.linux.elf_aux_maybe = auxv; | |
| 644 | __zig_elf_auxv = auxv; | |
| 642 | 645 | |
| 643 | 646 | if (!builtin.single_threaded) { |
| 644 | 647 | // ARMv6 targets (and earlier) have no support for TLS in hardware. |