diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 142c8d4e4a3275bb378c32219fb8f4dd5ccfe2a9..e5b2696f80984f0807b23153fb2d7b21b47abf2f 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -115,7 +115,6 @@ pub const user_desc = arch_bits.user_desc; pub const getcontext = arch_bits.getcontext; pub const tls = @import("linux/tls.zig"); -pub const pie = @import("linux/pie.zig"); pub const BPF = @import("linux/bpf.zig"); pub const IOCTL = @import("linux/ioctl.zig"); pub const SECCOMP = @import("linux/seccomp.zig"); diff --git a/lib/std/os/linux/pie.zig b/lib/std/os/linux/pie.zig deleted file mode 100644 index 572f3ddf96b020bc14ae80304cb67bb56f555402..0000000000000000000000000000000000000000 --- a/lib/std/os/linux/pie.zig +++ /dev/null @@ -1,304 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const elf = std.elf; -const assert = std.debug.assert; - -const R_AMD64_RELATIVE = 8; -const R_386_RELATIVE = 8; -const R_ARC_RELATIVE = 56; -const R_ARM_RELATIVE = 23; -const R_AARCH64_RELATIVE = 1027; -const R_CSKY_RELATIVE = 9; -const R_HEXAGON_RELATIVE = 35; -const R_LARCH_RELATIVE = 3; -const R_68K_RELATIVE = 22; -const R_MIPS_RELATIVE = 128; -const R_PPC_RELATIVE = 22; -const R_RISCV_RELATIVE = 3; -const R_390_RELATIVE = 12; -const R_SPARC_RELATIVE = 22; - -const R_RELATIVE = switch (builtin.cpu.arch) { - .x86 => R_386_RELATIVE, - .x86_64 => R_AMD64_RELATIVE, - .arc => R_ARC_RELATIVE, - .arm, .armeb, .thumb, .thumbeb => R_ARM_RELATIVE, - .aarch64, .aarch64_be => R_AARCH64_RELATIVE, - .csky => R_CSKY_RELATIVE, - .hexagon => R_HEXAGON_RELATIVE, - .loongarch32, .loongarch64 => R_LARCH_RELATIVE, - .m68k => R_68K_RELATIVE, - .mips, .mipsel, .mips64, .mips64el => R_MIPS_RELATIVE, - .powerpc, .powerpcle, .powerpc64, .powerpc64le => R_PPC_RELATIVE, - .riscv32, .riscv64 => R_RISCV_RELATIVE, - .s390x => R_390_RELATIVE, - .sparc, .sparc64 => R_SPARC_RELATIVE, - else => @compileError("Missing R_RELATIVE definition for this target"), -}; - -// Obtain a pointer to the _DYNAMIC array. -// We have to compute its address as a PC-relative quantity not to require a -// relocation that, at this point, is not yet applied. -inline fn getDynamicSymbol() [*]elf.Dyn { - return switch (builtin.cpu.arch) { - .x86 => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ call 1f - \\ 1: pop %[ret] - \\ lea _DYNAMIC-1b(%[ret]), %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - .x86_64 => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ lea _DYNAMIC(%%rip), %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - .arc => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ add %[ret], pcl, _DYNAMIC@pcl - : [ret] "=r" (-> [*]elf.Dyn), - ), - // Work around the limited offset range of `ldr` - .arm, .armeb, .thumb, .thumbeb => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ ldr %[ret], 1f - \\ add %[ret], pc - \\ b 2f - \\ 1: .word _DYNAMIC-1b - \\ 2: - : [ret] "=r" (-> [*]elf.Dyn), - ), - // A simple `adr` is not enough as it has a limited offset range - .aarch64, .aarch64_be => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ adrp %[ret], _DYNAMIC - \\ add %[ret], %[ret], #:lo12:_DYNAMIC - : [ret] "=r" (-> [*]elf.Dyn), - ), - // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first - // entry in the GOT is defined to hold the address of _DYNAMIC. - .csky => asm volatile ( - \\ mov %[ret], gb - \\ ldw %[ret], %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - .hexagon => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ jump 1f - \\ .word _DYNAMIC - . - \\ 1: - \\ r1 = pc - \\ r1 = add(r1, #-4) - \\ %[ret] = memw(r1) - \\ %[ret] = add(r1, %[ret]) - : [ret] "=r" (-> [*]elf.Dyn), - : - : "r1" - ), - .loongarch32, .loongarch64 => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ la.local %[ret], _DYNAMIC - : [ret] "=r" (-> [*]elf.Dyn), - ), - // Note that the - 8 is needed because pc in the second lea instruction points into the - // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.) - .m68k => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ lea _DYNAMIC - . - 8, %[ret] - \\ lea (%[ret], %%pc), %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - .mips, .mipsel => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ bal 1f - \\ .gpword _DYNAMIC - \\ 1: - \\ lw %[ret], 0($ra) - \\ addu %[ret], %[ret], $gp - : [ret] "=r" (-> [*]elf.Dyn), - : - : "lr" - ), - .mips64, .mips64el => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ .balign 8 - \\ bal 1f - \\ .gpdword _DYNAMIC - \\ 1: - \\ ld %[ret], 0($ra) - \\ daddu %[ret], %[ret], $gp - : [ret] "=r" (-> [*]elf.Dyn), - : - : "lr" - ), - .powerpc, .powerpcle => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ bl 1f - \\ .long _DYNAMIC - . - \\ 1: - \\ mflr %[ret] - \\ lwz 4, 0(%[ret]) - \\ add %[ret], 4, %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - : - : "lr", "r4" - ), - .powerpc64, .powerpc64le => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ bl 1f - \\ .quad _DYNAMIC - . - \\ 1: - \\ mflr %[ret] - \\ ld 4, 0(%[ret]) - \\ add %[ret], 4, %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - : - : "lr", "r4" - ), - .riscv32, .riscv64 => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ lla %[ret], _DYNAMIC - : [ret] "=r" (-> [*]elf.Dyn), - ), - .s390x => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ larl %[ret], 1f - \\ ag %[ret], 0(%[ret]) - \\ jg 2f - \\ 1: .quad _DYNAMIC - . - \\ 2: - : [ret] "=r" (-> [*]elf.Dyn), - ), - // The compiler does not necessarily have any obligation to load the `l7` register (pointing - // to the GOT), so do it ourselves just in case. - .sparc, .sparc64 => asm volatile ( - \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7 - \\ call 1f - \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7 - \\ 1: - \\ add %%l7, %%o7, %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - else => { - @compileError("PIE startup is not yet supported for this target!"); - }, - }; -} - -pub fn relocate(phdrs: []elf.Phdr) void { - @setRuntimeSafety(false); - @disableInstrumentation(); - - const dynv = getDynamicSymbol(); - - // Recover the delta applied by the loader by comparing the effective and - // the theoretical load addresses for the `_DYNAMIC` symbol. - const base_addr = base: { - for (phdrs) |*phdr| { - if (phdr.p_type != elf.PT_DYNAMIC) continue; - break :base @intFromPtr(dynv) - phdr.p_vaddr; - } - // This is not supposed to happen for well-formed binaries. - @trap(); - }; - - var sorted_dynv: [elf.DT_NUM]elf.Addr = undefined; - - // Zero-initialized this way to prevent the compiler from turning this into - // `memcpy` or `memset` calls (which can require relocations). - for (&sorted_dynv) |*dyn| { - const pdyn: *volatile elf.Addr = @ptrCast(dyn); - pdyn.* = 0; - } - - { - // `dynv` has no defined order. Fix that. - var i: usize = 0; - while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { - if (dynv[i].d_tag < elf.DT_NUM) sorted_dynv[@bitCast(dynv[i].d_tag)] = dynv[i].d_val; - } - } - - // Deal with the GOT relocations that MIPS uses first. - if (builtin.cpu.arch.isMIPS()) { - const count: elf.Addr = blk: { - // This is an architecture-specific tag, so not part of `sorted_dynv`. - var i: usize = 0; - while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { - if (dynv[i].d_tag == elf.DT_MIPS_LOCAL_GOTNO) break :blk dynv[i].d_val; - } - - break :blk 0; - }; - - const got: [*]usize = @ptrFromInt(base_addr + sorted_dynv[elf.DT_PLTGOT]); - - for (0..count) |i| { - got[i] += base_addr; - } - } - - // Apply normal relocations. - - const rel = sorted_dynv[elf.DT_REL]; - if (rel != 0) { - const rels = @call(.always_inline, std.mem.bytesAsSlice, .{ - elf.Rel, - @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]], - }); - for (rels) |r| { - if (r.r_type() != R_RELATIVE) continue; - @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; - } - } - - const rela = sorted_dynv[elf.DT_RELA]; - if (rela != 0) { - const relas = @call(.always_inline, std.mem.bytesAsSlice, .{ - elf.Rela, - @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]], - }); - for (relas) |r| { - if (r.r_type() != R_RELATIVE) continue; - @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); - } - } - - const relr = sorted_dynv[elf.DT_RELR]; - if (relr != 0) { - const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{ - elf.Relr, - @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]], - }); - var current: [*]usize = undefined; - for (relrs) |r| { - if ((r & 1) == 0) { - current = @ptrFromInt(base_addr + r); - current[0] += base_addr; - current += 1; - } else { - // Skip the first bit; there are 63 locations in the bitmap. - var i: if (@sizeOf(usize) == 8) u6 else u5 = 1; - while (i < @bitSizeOf(elf.Relr)) : (i += 1) { - if (((r >> i) & 1) != 0) current[i] += base_addr; - } - - current += @bitSizeOf(elf.Relr) - 1; - } - } - } -} diff --git a/lib/std/pie.zig b/lib/std/pie.zig new file mode 100644 index 0000000000000000000000000000000000000000..572f3ddf96b020bc14ae80304cb67bb56f555402 --- /dev/null +++ b/lib/std/pie.zig @@ -0,0 +1,304 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const elf = std.elf; +const assert = std.debug.assert; + +const R_AMD64_RELATIVE = 8; +const R_386_RELATIVE = 8; +const R_ARC_RELATIVE = 56; +const R_ARM_RELATIVE = 23; +const R_AARCH64_RELATIVE = 1027; +const R_CSKY_RELATIVE = 9; +const R_HEXAGON_RELATIVE = 35; +const R_LARCH_RELATIVE = 3; +const R_68K_RELATIVE = 22; +const R_MIPS_RELATIVE = 128; +const R_PPC_RELATIVE = 22; +const R_RISCV_RELATIVE = 3; +const R_390_RELATIVE = 12; +const R_SPARC_RELATIVE = 22; + +const R_RELATIVE = switch (builtin.cpu.arch) { + .x86 => R_386_RELATIVE, + .x86_64 => R_AMD64_RELATIVE, + .arc => R_ARC_RELATIVE, + .arm, .armeb, .thumb, .thumbeb => R_ARM_RELATIVE, + .aarch64, .aarch64_be => R_AARCH64_RELATIVE, + .csky => R_CSKY_RELATIVE, + .hexagon => R_HEXAGON_RELATIVE, + .loongarch32, .loongarch64 => R_LARCH_RELATIVE, + .m68k => R_68K_RELATIVE, + .mips, .mipsel, .mips64, .mips64el => R_MIPS_RELATIVE, + .powerpc, .powerpcle, .powerpc64, .powerpc64le => R_PPC_RELATIVE, + .riscv32, .riscv64 => R_RISCV_RELATIVE, + .s390x => R_390_RELATIVE, + .sparc, .sparc64 => R_SPARC_RELATIVE, + else => @compileError("Missing R_RELATIVE definition for this target"), +}; + +// Obtain a pointer to the _DYNAMIC array. +// We have to compute its address as a PC-relative quantity not to require a +// relocation that, at this point, is not yet applied. +inline fn getDynamicSymbol() [*]elf.Dyn { + return switch (builtin.cpu.arch) { + .x86 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ call 1f + \\ 1: pop %[ret] + \\ lea _DYNAMIC-1b(%[ret]), %[ret] + : [ret] "=r" (-> [*]elf.Dyn), + ), + .x86_64 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ lea _DYNAMIC(%%rip), %[ret] + : [ret] "=r" (-> [*]elf.Dyn), + ), + .arc => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ add %[ret], pcl, _DYNAMIC@pcl + : [ret] "=r" (-> [*]elf.Dyn), + ), + // Work around the limited offset range of `ldr` + .arm, .armeb, .thumb, .thumbeb => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ ldr %[ret], 1f + \\ add %[ret], pc + \\ b 2f + \\ 1: .word _DYNAMIC-1b + \\ 2: + : [ret] "=r" (-> [*]elf.Dyn), + ), + // A simple `adr` is not enough as it has a limited offset range + .aarch64, .aarch64_be => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ adrp %[ret], _DYNAMIC + \\ add %[ret], %[ret], #:lo12:_DYNAMIC + : [ret] "=r" (-> [*]elf.Dyn), + ), + // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first + // entry in the GOT is defined to hold the address of _DYNAMIC. + .csky => asm volatile ( + \\ mov %[ret], gb + \\ ldw %[ret], %[ret] + : [ret] "=r" (-> [*]elf.Dyn), + ), + .hexagon => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ jump 1f + \\ .word _DYNAMIC - . + \\ 1: + \\ r1 = pc + \\ r1 = add(r1, #-4) + \\ %[ret] = memw(r1) + \\ %[ret] = add(r1, %[ret]) + : [ret] "=r" (-> [*]elf.Dyn), + : + : "r1" + ), + .loongarch32, .loongarch64 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ la.local %[ret], _DYNAMIC + : [ret] "=r" (-> [*]elf.Dyn), + ), + // Note that the - 8 is needed because pc in the second lea instruction points into the + // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.) + .m68k => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ lea _DYNAMIC - . - 8, %[ret] + \\ lea (%[ret], %%pc), %[ret] + : [ret] "=r" (-> [*]elf.Dyn), + ), + .mips, .mipsel => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ bal 1f + \\ .gpword _DYNAMIC + \\ 1: + \\ lw %[ret], 0($ra) + \\ addu %[ret], %[ret], $gp + : [ret] "=r" (-> [*]elf.Dyn), + : + : "lr" + ), + .mips64, .mips64el => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ .balign 8 + \\ bal 1f + \\ .gpdword _DYNAMIC + \\ 1: + \\ ld %[ret], 0($ra) + \\ daddu %[ret], %[ret], $gp + : [ret] "=r" (-> [*]elf.Dyn), + : + : "lr" + ), + .powerpc, .powerpcle => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ bl 1f + \\ .long _DYNAMIC - . + \\ 1: + \\ mflr %[ret] + \\ lwz 4, 0(%[ret]) + \\ add %[ret], 4, %[ret] + : [ret] "=r" (-> [*]elf.Dyn), + : + : "lr", "r4" + ), + .powerpc64, .powerpc64le => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ bl 1f + \\ .quad _DYNAMIC - . + \\ 1: + \\ mflr %[ret] + \\ ld 4, 0(%[ret]) + \\ add %[ret], 4, %[ret] + : [ret] "=r" (-> [*]elf.Dyn), + : + : "lr", "r4" + ), + .riscv32, .riscv64 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ lla %[ret], _DYNAMIC + : [ret] "=r" (-> [*]elf.Dyn), + ), + .s390x => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ larl %[ret], 1f + \\ ag %[ret], 0(%[ret]) + \\ jg 2f + \\ 1: .quad _DYNAMIC - . + \\ 2: + : [ret] "=r" (-> [*]elf.Dyn), + ), + // The compiler does not necessarily have any obligation to load the `l7` register (pointing + // to the GOT), so do it ourselves just in case. + .sparc, .sparc64 => asm volatile ( + \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7 + \\ call 1f + \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7 + \\ 1: + \\ add %%l7, %%o7, %[ret] + : [ret] "=r" (-> [*]elf.Dyn), + ), + else => { + @compileError("PIE startup is not yet supported for this target!"); + }, + }; +} + +pub fn relocate(phdrs: []elf.Phdr) void { + @setRuntimeSafety(false); + @disableInstrumentation(); + + const dynv = getDynamicSymbol(); + + // Recover the delta applied by the loader by comparing the effective and + // the theoretical load addresses for the `_DYNAMIC` symbol. + const base_addr = base: { + for (phdrs) |*phdr| { + if (phdr.p_type != elf.PT_DYNAMIC) continue; + break :base @intFromPtr(dynv) - phdr.p_vaddr; + } + // This is not supposed to happen for well-formed binaries. + @trap(); + }; + + var sorted_dynv: [elf.DT_NUM]elf.Addr = undefined; + + // Zero-initialized this way to prevent the compiler from turning this into + // `memcpy` or `memset` calls (which can require relocations). + for (&sorted_dynv) |*dyn| { + const pdyn: *volatile elf.Addr = @ptrCast(dyn); + pdyn.* = 0; + } + + { + // `dynv` has no defined order. Fix that. + var i: usize = 0; + while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { + if (dynv[i].d_tag < elf.DT_NUM) sorted_dynv[@bitCast(dynv[i].d_tag)] = dynv[i].d_val; + } + } + + // Deal with the GOT relocations that MIPS uses first. + if (builtin.cpu.arch.isMIPS()) { + const count: elf.Addr = blk: { + // This is an architecture-specific tag, so not part of `sorted_dynv`. + var i: usize = 0; + while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { + if (dynv[i].d_tag == elf.DT_MIPS_LOCAL_GOTNO) break :blk dynv[i].d_val; + } + + break :blk 0; + }; + + const got: [*]usize = @ptrFromInt(base_addr + sorted_dynv[elf.DT_PLTGOT]); + + for (0..count) |i| { + got[i] += base_addr; + } + } + + // Apply normal relocations. + + const rel = sorted_dynv[elf.DT_REL]; + if (rel != 0) { + const rels = @call(.always_inline, std.mem.bytesAsSlice, .{ + elf.Rel, + @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]], + }); + for (rels) |r| { + if (r.r_type() != R_RELATIVE) continue; + @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; + } + } + + const rela = sorted_dynv[elf.DT_RELA]; + if (rela != 0) { + const relas = @call(.always_inline, std.mem.bytesAsSlice, .{ + elf.Rela, + @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]], + }); + for (relas) |r| { + if (r.r_type() != R_RELATIVE) continue; + @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); + } + } + + const relr = sorted_dynv[elf.DT_RELR]; + if (relr != 0) { + const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{ + elf.Relr, + @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]], + }); + var current: [*]usize = undefined; + for (relrs) |r| { + if ((r & 1) == 0) { + current = @ptrFromInt(base_addr + r); + current[0] += base_addr; + current += 1; + } else { + // Skip the first bit; there are 63 locations in the bitmap. + var i: if (@sizeOf(usize) == 8) u6 else u5 = 1; + while (i < @bitSizeOf(elf.Relr)) : (i += 1) { + if (((r >> i) & 1) != 0) current[i] += base_addr; + } + + current += @bitSizeOf(elf.Relr) - 1; + } + } + } +} diff --git a/lib/std/start.zig b/lib/std/start.zig index 6495db1c51a67b77d82a8bda766e95774c59b321..477e24bb557c4b0e1f740839e59b312d019eaa9e 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -325,7 +325,7 @@ fn _start() callconv(.naked) noreturn { , .csky => // The CSKY ABI assumes that `gb` is set to the address of the GOT in order for - // position-independent code to work. We depend on this in `std.os.linux.pie` to locate + // position-independent code to work. We depend on this in `std.pie` to locate // `_DYNAMIC` as well. // r8 = FP \\ grs t0, 1f @@ -514,33 +514,33 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { while (envp_optional[envp_count]) |_| : (envp_count += 1) {} const envp = @as([*][*:0]u8, @ptrCast(envp_optional))[0..envp_count]; + // Find the beginning of the auxiliary vector + const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1)); + + var at_hwcap: usize = 0; + const phdrs = init: { + var i: usize = 0; + var at_phdr: usize = 0; + var at_phnum: usize = 0; + while (auxv[i].a_type != elf.AT_NULL) : (i += 1) { + switch (auxv[i].a_type) { + elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, + elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, + elf.AT_HWCAP => at_hwcap = auxv[i].a_un.a_val, + else => continue, + } + } + break :init @as([*]elf.Phdr, @ptrFromInt(at_phdr))[0..at_phnum]; + }; + + // Apply the initial relocations as early as possible in the startup process. We cannot + // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet, + // so this must be fully inlined. + if (builtin.position_independent_executable) { + @call(.always_inline, std.pie.relocate, .{phdrs}); + } + if (native_os == .linux) { - // Find the beginning of the auxiliary vector - const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1)); - - var at_hwcap: usize = 0; - const phdrs = init: { - var i: usize = 0; - var at_phdr: usize = 0; - var at_phnum: usize = 0; - while (auxv[i].a_type != elf.AT_NULL) : (i += 1) { - switch (auxv[i].a_type) { - elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, - elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, - elf.AT_HWCAP => at_hwcap = auxv[i].a_un.a_val, - else => continue, - } - } - break :init @as([*]elf.Phdr, @ptrFromInt(at_phdr))[0..at_phnum]; - }; - - // Apply the initial relocations as early as possible in the startup process. We cannot - // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet, - // so this must be fully inlined. - if (builtin.position_independent_executable) { - @call(.always_inline, std.os.linux.pie.relocate, .{phdrs}); - } - // 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; @@ -567,20 +567,20 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { // Here we look for the stack size in our program headers and use setrlimit // to ask for more stack space. expandStackSize(phdrs); + } - const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{ - .name = "__init_array_start", - .linkage = .weak, - }); - const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{ - .name = "__init_array_end", - .linkage = .weak, - }); - if (opt_init_array_start) |init_array_start| { - const init_array_end = opt_init_array_end.?; - const slice = init_array_start[0 .. init_array_end - init_array_start]; - for (slice) |func| func(); - } + const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{ + .name = "__init_array_start", + .linkage = .weak, + }); + const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{ + .name = "__init_array_end", + .linkage = .weak, + }); + if (opt_init_array_start) |init_array_start| { + const init_array_end = opt_init_array_end.?; + const slice = init_array_start[0 .. init_array_end - init_array_start]; + for (slice) |func| func(); } std.posix.exit(callMainWithArgs(argc, argv, envp)); diff --git a/lib/std/std.zig b/lib/std/std.zig index 94851657a680779fc2423aa37fa6285f18bacd36..5f13b931d1d1f18790c9dbb4501ca59f2b0433ec 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -79,6 +79,7 @@ pub const net = @import("net.zig"); pub const os = @import("os.zig"); pub const once = @import("once.zig").once; pub const pdb = @import("pdb.zig"); +pub const pie = @import("pie.zig"); pub const posix = @import("posix.zig"); pub const process = @import("process.zig"); pub const sort = @import("sort.zig");