diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 5660847ce84fbbedc64d4e980202e3865f8df592..e4d4824a38654c26da6a763f75e8df8cfd408681 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -164,6 +164,8 @@ comptime { symbol(&strlen, "strlen"); } + _ = @import("compiler_rt/elf.zig"); + // Temporarily used for uefi until https://github.com/ziglang/zig/issues/21630 is addressed. if (!builtin.link_libc and (builtin.os.tag == .windows or builtin.os.tag == .uefi) and (builtin.abi == .none or builtin.abi == .msvc)) { symbol(&_fltused, "_fltused"); diff --git a/lib/compiler_rt/elf.zig b/lib/compiler_rt/elf.zig new file mode 100644 index 0000000000000000000000000000000000000000..e68d5ad7c459cccfc3fefe34739507349a5ed350 --- /dev/null +++ b/lib/compiler_rt/elf.zig @@ -0,0 +1,3 @@ +comptime { + _ = @import("elf/auxv.zig"); +} diff --git a/lib/compiler_rt/elf/auxv.zig b/lib/compiler_rt/elf/auxv.zig new file mode 100644 index 0000000000000000000000000000000000000000..de5a45e501b5850f8f25aa18ffec75ccf23927ac --- /dev/null +++ b/lib/compiler_rt/elf/auxv.zig @@ -0,0 +1,21 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const compiler_rt = @import("../../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + // FreeBSD, NetBSD, and OpenBSD are expected to also use this in the future. + if (!builtin.link_libc and builtin.target.os.tag == .linux) { + symbol(@ptrCast(&__zig_elf_auxv), "__zig_elf_auxv"); + } +} + +/// Populated by `std.start` when libc is not linked on targets that provide an ELF auxiliary vector +/// to the process on startup. Provided by compiler-rt so that there is no confusion about where +/// this state lives regardless of how the final artifact (executable or shared library) is +/// compiled. +/// +/// It is expected that this will gradually be replaced with better mechanisms as operating systems +/// improve; see https://codeberg.org/ziglang/zig/issues/31290. +var __zig_elf_auxv: [*]std.elf.Auxv = undefined; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 38e4abd197ba6c17245e7fe7038d7db0528ca395..e75a0d822467481b245997d4818989a9c7654b50 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -960,43 +960,22 @@ pub const RENAME = packed struct(u32) { _: u29 = 0, }; -/// Set by startup code, used by `getauxval`. -pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; +/// Available only when libc is *not* linked; use `std.c.getauxval` if libc is linked. +pub const getauxval = if (builtin.link_libc) {} else struct { + /// Provided by compiler-rt and set by `std.start`. + extern var __zig_elf_auxv: [*]std.elf.Auxv; -/// Whether an external or internal getauxval implementation is used. -const extern_getauxval = switch (builtin.zig_backend) { - // Calling extern functions is not yet supported with these backends - .stage2_arm, - .stage2_loongarch, - .stage2_powerpc, - .stage2_riscv64, - .stage2_sparc64, - => false, - else => !builtin.link_libc, -}; + pub fn getauxval(index: usize) usize { + @disableInstrumentation(); -pub const getauxval = if (extern_getauxval) struct { - comptime { - const root = @import("root"); - // Export this only when building an executable, otherwise it is overriding - // the libc implementation - if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { - @export(&getauxvalImpl, .{ .name = "getauxval", .linkage = .weak }); + var i: usize = 0; + while (__zig_elf_auxv[i].a_type != std.elf.AT.NULL) : (i += 1) { + if (__zig_elf_auxv[i].a_type == index) return __zig_elf_auxv[i].a_un.a_val; } - } - extern fn getauxval(index: usize) usize; -}.getauxval else getauxvalImpl; -fn getauxvalImpl(index: usize) callconv(.c) usize { - @disableInstrumentation(); - const auxv = elf_aux_maybe orelse return 0; - var i: usize = 0; - while (auxv[i].a_type != std.elf.AT.NULL) : (i += 1) { - if (auxv[i].a_type == index) - return auxv[i].a_un.a_val; + return 0; } - return 0; -} +}.getauxval; // Some architectures (and some syscalls) require 64bit parameters to be passed // in a even-aligned register pair. diff --git a/lib/std/os/linux/vdso.zig b/lib/std/os/linux/vdso.zig index bdf46337b59ecc863a543d3722ddf47bd967374a..5add23f5c42bd6f93cfdc39825b42cc969d8e321 100644 --- a/lib/std/os/linux/vdso.zig +++ b/lib/std/os/linux/vdso.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const elf = std.elf; const linux = std.os.linux; @@ -5,7 +6,8 @@ const mem = std.mem; const maxInt = std.math.maxInt; pub fn lookup(vername: []const u8, name: []const u8) usize { - const vdso_addr = linux.getauxval(std.elf.AT.SYSINFO_EHDR); + const getauxval = if (builtin.link_libc) std.c.getauxval else linux.getauxval; + const vdso_addr = getauxval(std.elf.AT.SYSINFO_EHDR); if (vdso_addr == 0) return 0; const eh = @as(*elf.Ehdr, @ptrFromInt(vdso_addr)); diff --git a/lib/std/start.zig b/lib/std/start.zig index 96190d835614718793d94832f9a0b72e415d964d..f8c85adeded05726074c5ed0516b336892d34154 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -596,6 +596,9 @@ fn wWinMain(hInstance: *anyopaque, hPrevInstance: ?*anyopaque, pCmdLine: [*:0]u1 return root.wWinMain(@ptrCast(hInstance), @ptrCast(hPrevInstance), pCmdLine, @intCast(nCmdShow)); } +/// Provided by compiler-rt. +extern var __zig_elf_auxv: [*]std.elf.Auxv; + fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { // We're not ready to panic until thread local storage is initialized. @setRuntimeSafety(false); @@ -638,7 +641,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { if (native_os == .linux) { // This must be done after PIE relocations have been applied or we may crash // while trying to access the global variable (happens on MIPS at least). - std.os.linux.elf_aux_maybe = auxv; + __zig_elf_auxv = auxv; if (!builtin.single_threaded) { // ARMv6 targets (and earlier) have no support for TLS in hardware.