| author | |
| committer | |
| log | 74a3ae492797b1b2cf1936f0c91560585efdf6c6 |
| tree | ba520c805a8f89d85dbe51dafd4c405bf2fa65b6 |
| parent | 8e72a25285b5e782ee44828b6d1904d91fb16a29 |
This code applies to ~any POSIX OS where we don't link libc. For example, it'll
be useful for FreeBSD and NetBSD.
As part of this, move std.os.linux.pie to std.pie since there's really nothing
Linux-specific about what that file is doing.5 files changed, 343 insertions(+), 343 deletions(-)
lib/std/os/linux.zig-1| ... | @@ -115,7 +115,6 @@ pub const user_desc = arch_bits.user_desc; | ... | @@ -115,7 +115,6 @@ pub const user_desc = arch_bits.user_desc; |
| 115 | pub const getcontext = arch_bits.getcontext; | 115 | pub const getcontext = arch_bits.getcontext; |
| 116 | 116 | ||
| 117 | pub const tls = @import("linux/tls.zig"); | 117 | pub const tls = @import("linux/tls.zig"); |
| 118 | pub const pie = @import("linux/pie.zig"); | ||
| 119 | pub const BPF = @import("linux/bpf.zig"); | 118 | pub const BPF = @import("linux/bpf.zig"); |
| 120 | pub const IOCTL = @import("linux/ioctl.zig"); | 119 | pub const IOCTL = @import("linux/ioctl.zig"); |
| 121 | pub const SECCOMP = @import("linux/seccomp.zig"); | 120 | pub const SECCOMP = @import("linux/seccomp.zig"); |
lib/std/os/linux/pie.zig deleted-304| ... | @@ -1,304 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const elf = std.elf; | ||
| 4 | const assert = std.debug.assert; | ||
| 5 | |||
| 6 | const R_AMD64_RELATIVE = 8; | ||
| 7 | const R_386_RELATIVE = 8; | ||
| 8 | const R_ARC_RELATIVE = 56; | ||
| 9 | const R_ARM_RELATIVE = 23; | ||
| 10 | const R_AARCH64_RELATIVE = 1027; | ||
| 11 | const R_CSKY_RELATIVE = 9; | ||
| 12 | const R_HEXAGON_RELATIVE = 35; | ||
| 13 | const R_LARCH_RELATIVE = 3; | ||
| 14 | const R_68K_RELATIVE = 22; | ||
| 15 | const R_MIPS_RELATIVE = 128; | ||
| 16 | const R_PPC_RELATIVE = 22; | ||
| 17 | const R_RISCV_RELATIVE = 3; | ||
| 18 | const R_390_RELATIVE = 12; | ||
| 19 | const R_SPARC_RELATIVE = 22; | ||
| 20 | |||
| 21 | const R_RELATIVE = switch (builtin.cpu.arch) { | ||
| 22 | .x86 => R_386_RELATIVE, | ||
| 23 | .x86_64 => R_AMD64_RELATIVE, | ||
| 24 | .arc => R_ARC_RELATIVE, | ||
| 25 | .arm, .armeb, .thumb, .thumbeb => R_ARM_RELATIVE, | ||
| 26 | .aarch64, .aarch64_be => R_AARCH64_RELATIVE, | ||
| 27 | .csky => R_CSKY_RELATIVE, | ||
| 28 | .hexagon => R_HEXAGON_RELATIVE, | ||
| 29 | .loongarch32, .loongarch64 => R_LARCH_RELATIVE, | ||
| 30 | .m68k => R_68K_RELATIVE, | ||
| 31 | .mips, .mipsel, .mips64, .mips64el => R_MIPS_RELATIVE, | ||
| 32 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => R_PPC_RELATIVE, | ||
| 33 | .riscv32, .riscv64 => R_RISCV_RELATIVE, | ||
| 34 | .s390x => R_390_RELATIVE, | ||
| 35 | .sparc, .sparc64 => R_SPARC_RELATIVE, | ||
| 36 | else => @compileError("Missing R_RELATIVE definition for this target"), | ||
| 37 | }; | ||
| 38 | |||
| 39 | // Obtain a pointer to the _DYNAMIC array. | ||
| 40 | // We have to compute its address as a PC-relative quantity not to require a | ||
| 41 | // relocation that, at this point, is not yet applied. | ||
| 42 | inline fn getDynamicSymbol() [*]elf.Dyn { | ||
| 43 | return switch (builtin.cpu.arch) { | ||
| 44 | .x86 => asm volatile ( | ||
| 45 | \\ .weak _DYNAMIC | ||
| 46 | \\ .hidden _DYNAMIC | ||
| 47 | \\ call 1f | ||
| 48 | \\ 1: pop %[ret] | ||
| 49 | \\ lea _DYNAMIC-1b(%[ret]), %[ret] | ||
| 50 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 51 | ), | ||
| 52 | .x86_64 => asm volatile ( | ||
| 53 | \\ .weak _DYNAMIC | ||
| 54 | \\ .hidden _DYNAMIC | ||
| 55 | \\ lea _DYNAMIC(%%rip), %[ret] | ||
| 56 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 57 | ), | ||
| 58 | .arc => asm volatile ( | ||
| 59 | \\ .weak _DYNAMIC | ||
| 60 | \\ .hidden _DYNAMIC | ||
| 61 | \\ add %[ret], pcl, _DYNAMIC@pcl | ||
| 62 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 63 | ), | ||
| 64 | // Work around the limited offset range of `ldr` | ||
| 65 | .arm, .armeb, .thumb, .thumbeb => asm volatile ( | ||
| 66 | \\ .weak _DYNAMIC | ||
| 67 | \\ .hidden _DYNAMIC | ||
| 68 | \\ ldr %[ret], 1f | ||
| 69 | \\ add %[ret], pc | ||
| 70 | \\ b 2f | ||
| 71 | \\ 1: .word _DYNAMIC-1b | ||
| 72 | \\ 2: | ||
| 73 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 74 | ), | ||
| 75 | // A simple `adr` is not enough as it has a limited offset range | ||
| 76 | .aarch64, .aarch64_be => asm volatile ( | ||
| 77 | \\ .weak _DYNAMIC | ||
| 78 | \\ .hidden _DYNAMIC | ||
| 79 | \\ adrp %[ret], _DYNAMIC | ||
| 80 | \\ add %[ret], %[ret], #:lo12:_DYNAMIC | ||
| 81 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 82 | ), | ||
| 83 | // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first | ||
| 84 | // entry in the GOT is defined to hold the address of _DYNAMIC. | ||
| 85 | .csky => asm volatile ( | ||
| 86 | \\ mov %[ret], gb | ||
| 87 | \\ ldw %[ret], %[ret] | ||
| 88 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 89 | ), | ||
| 90 | .hexagon => asm volatile ( | ||
| 91 | \\ .weak _DYNAMIC | ||
| 92 | \\ .hidden _DYNAMIC | ||
| 93 | \\ jump 1f | ||
| 94 | \\ .word _DYNAMIC - . | ||
| 95 | \\ 1: | ||
| 96 | \\ r1 = pc | ||
| 97 | \\ r1 = add(r1, #-4) | ||
| 98 | \\ %[ret] = memw(r1) | ||
| 99 | \\ %[ret] = add(r1, %[ret]) | ||
| 100 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 101 | : | ||
| 102 | : "r1" | ||
| 103 | ), | ||
| 104 | .loongarch32, .loongarch64 => asm volatile ( | ||
| 105 | \\ .weak _DYNAMIC | ||
| 106 | \\ .hidden _DYNAMIC | ||
| 107 | \\ la.local %[ret], _DYNAMIC | ||
| 108 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 109 | ), | ||
| 110 | // Note that the - 8 is needed because pc in the second lea instruction points into the | ||
| 111 | // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.) | ||
| 112 | .m68k => asm volatile ( | ||
| 113 | \\ .weak _DYNAMIC | ||
| 114 | \\ .hidden _DYNAMIC | ||
| 115 | \\ lea _DYNAMIC - . - 8, %[ret] | ||
| 116 | \\ lea (%[ret], %%pc), %[ret] | ||
| 117 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 118 | ), | ||
| 119 | .mips, .mipsel => asm volatile ( | ||
| 120 | \\ .weak _DYNAMIC | ||
| 121 | \\ .hidden _DYNAMIC | ||
| 122 | \\ bal 1f | ||
| 123 | \\ .gpword _DYNAMIC | ||
| 124 | \\ 1: | ||
| 125 | \\ lw %[ret], 0($ra) | ||
| 126 | \\ addu %[ret], %[ret], $gp | ||
| 127 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 128 | : | ||
| 129 | : "lr" | ||
| 130 | ), | ||
| 131 | .mips64, .mips64el => asm volatile ( | ||
| 132 | \\ .weak _DYNAMIC | ||
| 133 | \\ .hidden _DYNAMIC | ||
| 134 | \\ .balign 8 | ||
| 135 | \\ bal 1f | ||
| 136 | \\ .gpdword _DYNAMIC | ||
| 137 | \\ 1: | ||
| 138 | \\ ld %[ret], 0($ra) | ||
| 139 | \\ daddu %[ret], %[ret], $gp | ||
| 140 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 141 | : | ||
| 142 | : "lr" | ||
| 143 | ), | ||
| 144 | .powerpc, .powerpcle => asm volatile ( | ||
| 145 | \\ .weak _DYNAMIC | ||
| 146 | \\ .hidden _DYNAMIC | ||
| 147 | \\ bl 1f | ||
| 148 | \\ .long _DYNAMIC - . | ||
| 149 | \\ 1: | ||
| 150 | \\ mflr %[ret] | ||
| 151 | \\ lwz 4, 0(%[ret]) | ||
| 152 | \\ add %[ret], 4, %[ret] | ||
| 153 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 154 | : | ||
| 155 | : "lr", "r4" | ||
| 156 | ), | ||
| 157 | .powerpc64, .powerpc64le => asm volatile ( | ||
| 158 | \\ .weak _DYNAMIC | ||
| 159 | \\ .hidden _DYNAMIC | ||
| 160 | \\ bl 1f | ||
| 161 | \\ .quad _DYNAMIC - . | ||
| 162 | \\ 1: | ||
| 163 | \\ mflr %[ret] | ||
| 164 | \\ ld 4, 0(%[ret]) | ||
| 165 | \\ add %[ret], 4, %[ret] | ||
| 166 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 167 | : | ||
| 168 | : "lr", "r4" | ||
| 169 | ), | ||
| 170 | .riscv32, .riscv64 => asm volatile ( | ||
| 171 | \\ .weak _DYNAMIC | ||
| 172 | \\ .hidden _DYNAMIC | ||
| 173 | \\ lla %[ret], _DYNAMIC | ||
| 174 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 175 | ), | ||
| 176 | .s390x => asm volatile ( | ||
| 177 | \\ .weak _DYNAMIC | ||
| 178 | \\ .hidden _DYNAMIC | ||
| 179 | \\ larl %[ret], 1f | ||
| 180 | \\ ag %[ret], 0(%[ret]) | ||
| 181 | \\ jg 2f | ||
| 182 | \\ 1: .quad _DYNAMIC - . | ||
| 183 | \\ 2: | ||
| 184 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 185 | ), | ||
| 186 | // The compiler does not necessarily have any obligation to load the `l7` register (pointing | ||
| 187 | // to the GOT), so do it ourselves just in case. | ||
| 188 | .sparc, .sparc64 => asm volatile ( | ||
| 189 | \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7 | ||
| 190 | \\ call 1f | ||
| 191 | \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7 | ||
| 192 | \\ 1: | ||
| 193 | \\ add %%l7, %%o7, %[ret] | ||
| 194 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 195 | ), | ||
| 196 | else => { | ||
| 197 | @compileError("PIE startup is not yet supported for this target!"); | ||
| 198 | }, | ||
| 199 | }; | ||
| 200 | } | ||
| 201 | |||
| 202 | pub fn relocate(phdrs: []elf.Phdr) void { | ||
| 203 | @setRuntimeSafety(false); | ||
| 204 | @disableInstrumentation(); | ||
| 205 | |||
| 206 | const dynv = getDynamicSymbol(); | ||
| 207 | |||
| 208 | // Recover the delta applied by the loader by comparing the effective and | ||
| 209 | // the theoretical load addresses for the `_DYNAMIC` symbol. | ||
| 210 | const base_addr = base: { | ||
| 211 | for (phdrs) |*phdr| { | ||
| 212 | if (phdr.p_type != elf.PT_DYNAMIC) continue; | ||
| 213 | break :base @intFromPtr(dynv) - phdr.p_vaddr; | ||
| 214 | } | ||
| 215 | // This is not supposed to happen for well-formed binaries. | ||
| 216 | @trap(); | ||
| 217 | }; | ||
| 218 | |||
| 219 | var sorted_dynv: [elf.DT_NUM]elf.Addr = undefined; | ||
| 220 | |||
| 221 | // Zero-initialized this way to prevent the compiler from turning this into | ||
| 222 | // `memcpy` or `memset` calls (which can require relocations). | ||
| 223 | for (&sorted_dynv) |*dyn| { | ||
| 224 | const pdyn: *volatile elf.Addr = @ptrCast(dyn); | ||
| 225 | pdyn.* = 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | { | ||
| 229 | // `dynv` has no defined order. Fix that. | ||
| 230 | var i: usize = 0; | ||
| 231 | while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { | ||
| 232 | if (dynv[i].d_tag < elf.DT_NUM) sorted_dynv[@bitCast(dynv[i].d_tag)] = dynv[i].d_val; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | // Deal with the GOT relocations that MIPS uses first. | ||
| 237 | if (builtin.cpu.arch.isMIPS()) { | ||
| 238 | const count: elf.Addr = blk: { | ||
| 239 | // This is an architecture-specific tag, so not part of `sorted_dynv`. | ||
| 240 | var i: usize = 0; | ||
| 241 | while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { | ||
| 242 | if (dynv[i].d_tag == elf.DT_MIPS_LOCAL_GOTNO) break :blk dynv[i].d_val; | ||
| 243 | } | ||
| 244 | |||
| 245 | break :blk 0; | ||
| 246 | }; | ||
| 247 | |||
| 248 | const got: [*]usize = @ptrFromInt(base_addr + sorted_dynv[elf.DT_PLTGOT]); | ||
| 249 | |||
| 250 | for (0..count) |i| { | ||
| 251 | got[i] += base_addr; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | // Apply normal relocations. | ||
| 256 | |||
| 257 | const rel = sorted_dynv[elf.DT_REL]; | ||
| 258 | if (rel != 0) { | ||
| 259 | const rels = @call(.always_inline, std.mem.bytesAsSlice, .{ | ||
| 260 | elf.Rel, | ||
| 261 | @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]], | ||
| 262 | }); | ||
| 263 | for (rels) |r| { | ||
| 264 | if (r.r_type() != R_RELATIVE) continue; | ||
| 265 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | const rela = sorted_dynv[elf.DT_RELA]; | ||
| 270 | if (rela != 0) { | ||
| 271 | const relas = @call(.always_inline, std.mem.bytesAsSlice, .{ | ||
| 272 | elf.Rela, | ||
| 273 | @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]], | ||
| 274 | }); | ||
| 275 | for (relas) |r| { | ||
| 276 | if (r.r_type() != R_RELATIVE) continue; | ||
| 277 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | const relr = sorted_dynv[elf.DT_RELR]; | ||
| 282 | if (relr != 0) { | ||
| 283 | const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{ | ||
| 284 | elf.Relr, | ||
| 285 | @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]], | ||
| 286 | }); | ||
| 287 | var current: [*]usize = undefined; | ||
| 288 | for (relrs) |r| { | ||
| 289 | if ((r & 1) == 0) { | ||
| 290 | current = @ptrFromInt(base_addr + r); | ||
| 291 | current[0] += base_addr; | ||
| 292 | current += 1; | ||
| 293 | } else { | ||
| 294 | // Skip the first bit; there are 63 locations in the bitmap. | ||
| 295 | var i: if (@sizeOf(usize) == 8) u6 else u5 = 1; | ||
| 296 | while (i < @bitSizeOf(elf.Relr)) : (i += 1) { | ||
| 297 | if (((r >> i) & 1) != 0) current[i] += base_addr; | ||
| 298 | } | ||
| 299 | |||
| 300 | current += @bitSizeOf(elf.Relr) - 1; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | } | ||
| 304 | } | ||
lib/std/pie.zig created+304| ... | @@ -0,0 +1,304 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const elf = std.elf; | ||
| 4 | const assert = std.debug.assert; | ||
| 5 | |||
| 6 | const R_AMD64_RELATIVE = 8; | ||
| 7 | const R_386_RELATIVE = 8; | ||
| 8 | const R_ARC_RELATIVE = 56; | ||
| 9 | const R_ARM_RELATIVE = 23; | ||
| 10 | const R_AARCH64_RELATIVE = 1027; | ||
| 11 | const R_CSKY_RELATIVE = 9; | ||
| 12 | const R_HEXAGON_RELATIVE = 35; | ||
| 13 | const R_LARCH_RELATIVE = 3; | ||
| 14 | const R_68K_RELATIVE = 22; | ||
| 15 | const R_MIPS_RELATIVE = 128; | ||
| 16 | const R_PPC_RELATIVE = 22; | ||
| 17 | const R_RISCV_RELATIVE = 3; | ||
| 18 | const R_390_RELATIVE = 12; | ||
| 19 | const R_SPARC_RELATIVE = 22; | ||
| 20 | |||
| 21 | const R_RELATIVE = switch (builtin.cpu.arch) { | ||
| 22 | .x86 => R_386_RELATIVE, | ||
| 23 | .x86_64 => R_AMD64_RELATIVE, | ||
| 24 | .arc => R_ARC_RELATIVE, | ||
| 25 | .arm, .armeb, .thumb, .thumbeb => R_ARM_RELATIVE, | ||
| 26 | .aarch64, .aarch64_be => R_AARCH64_RELATIVE, | ||
| 27 | .csky => R_CSKY_RELATIVE, | ||
| 28 | .hexagon => R_HEXAGON_RELATIVE, | ||
| 29 | .loongarch32, .loongarch64 => R_LARCH_RELATIVE, | ||
| 30 | .m68k => R_68K_RELATIVE, | ||
| 31 | .mips, .mipsel, .mips64, .mips64el => R_MIPS_RELATIVE, | ||
| 32 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => R_PPC_RELATIVE, | ||
| 33 | .riscv32, .riscv64 => R_RISCV_RELATIVE, | ||
| 34 | .s390x => R_390_RELATIVE, | ||
| 35 | .sparc, .sparc64 => R_SPARC_RELATIVE, | ||
| 36 | else => @compileError("Missing R_RELATIVE definition for this target"), | ||
| 37 | }; | ||
| 38 | |||
| 39 | // Obtain a pointer to the _DYNAMIC array. | ||
| 40 | // We have to compute its address as a PC-relative quantity not to require a | ||
| 41 | // relocation that, at this point, is not yet applied. | ||
| 42 | inline fn getDynamicSymbol() [*]elf.Dyn { | ||
| 43 | return switch (builtin.cpu.arch) { | ||
| 44 | .x86 => asm volatile ( | ||
| 45 | \\ .weak _DYNAMIC | ||
| 46 | \\ .hidden _DYNAMIC | ||
| 47 | \\ call 1f | ||
| 48 | \\ 1: pop %[ret] | ||
| 49 | \\ lea _DYNAMIC-1b(%[ret]), %[ret] | ||
| 50 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 51 | ), | ||
| 52 | .x86_64 => asm volatile ( | ||
| 53 | \\ .weak _DYNAMIC | ||
| 54 | \\ .hidden _DYNAMIC | ||
| 55 | \\ lea _DYNAMIC(%%rip), %[ret] | ||
| 56 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 57 | ), | ||
| 58 | .arc => asm volatile ( | ||
| 59 | \\ .weak _DYNAMIC | ||
| 60 | \\ .hidden _DYNAMIC | ||
| 61 | \\ add %[ret], pcl, _DYNAMIC@pcl | ||
| 62 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 63 | ), | ||
| 64 | // Work around the limited offset range of `ldr` | ||
| 65 | .arm, .armeb, .thumb, .thumbeb => asm volatile ( | ||
| 66 | \\ .weak _DYNAMIC | ||
| 67 | \\ .hidden _DYNAMIC | ||
| 68 | \\ ldr %[ret], 1f | ||
| 69 | \\ add %[ret], pc | ||
| 70 | \\ b 2f | ||
| 71 | \\ 1: .word _DYNAMIC-1b | ||
| 72 | \\ 2: | ||
| 73 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 74 | ), | ||
| 75 | // A simple `adr` is not enough as it has a limited offset range | ||
| 76 | .aarch64, .aarch64_be => asm volatile ( | ||
| 77 | \\ .weak _DYNAMIC | ||
| 78 | \\ .hidden _DYNAMIC | ||
| 79 | \\ adrp %[ret], _DYNAMIC | ||
| 80 | \\ add %[ret], %[ret], #:lo12:_DYNAMIC | ||
| 81 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 82 | ), | ||
| 83 | // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first | ||
| 84 | // entry in the GOT is defined to hold the address of _DYNAMIC. | ||
| 85 | .csky => asm volatile ( | ||
| 86 | \\ mov %[ret], gb | ||
| 87 | \\ ldw %[ret], %[ret] | ||
| 88 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 89 | ), | ||
| 90 | .hexagon => asm volatile ( | ||
| 91 | \\ .weak _DYNAMIC | ||
| 92 | \\ .hidden _DYNAMIC | ||
| 93 | \\ jump 1f | ||
| 94 | \\ .word _DYNAMIC - . | ||
| 95 | \\ 1: | ||
| 96 | \\ r1 = pc | ||
| 97 | \\ r1 = add(r1, #-4) | ||
| 98 | \\ %[ret] = memw(r1) | ||
| 99 | \\ %[ret] = add(r1, %[ret]) | ||
| 100 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 101 | : | ||
| 102 | : "r1" | ||
| 103 | ), | ||
| 104 | .loongarch32, .loongarch64 => asm volatile ( | ||
| 105 | \\ .weak _DYNAMIC | ||
| 106 | \\ .hidden _DYNAMIC | ||
| 107 | \\ la.local %[ret], _DYNAMIC | ||
| 108 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 109 | ), | ||
| 110 | // Note that the - 8 is needed because pc in the second lea instruction points into the | ||
| 111 | // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.) | ||
| 112 | .m68k => asm volatile ( | ||
| 113 | \\ .weak _DYNAMIC | ||
| 114 | \\ .hidden _DYNAMIC | ||
| 115 | \\ lea _DYNAMIC - . - 8, %[ret] | ||
| 116 | \\ lea (%[ret], %%pc), %[ret] | ||
| 117 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 118 | ), | ||
| 119 | .mips, .mipsel => asm volatile ( | ||
| 120 | \\ .weak _DYNAMIC | ||
| 121 | \\ .hidden _DYNAMIC | ||
| 122 | \\ bal 1f | ||
| 123 | \\ .gpword _DYNAMIC | ||
| 124 | \\ 1: | ||
| 125 | \\ lw %[ret], 0($ra) | ||
| 126 | \\ addu %[ret], %[ret], $gp | ||
| 127 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 128 | : | ||
| 129 | : "lr" | ||
| 130 | ), | ||
| 131 | .mips64, .mips64el => asm volatile ( | ||
| 132 | \\ .weak _DYNAMIC | ||
| 133 | \\ .hidden _DYNAMIC | ||
| 134 | \\ .balign 8 | ||
| 135 | \\ bal 1f | ||
| 136 | \\ .gpdword _DYNAMIC | ||
| 137 | \\ 1: | ||
| 138 | \\ ld %[ret], 0($ra) | ||
| 139 | \\ daddu %[ret], %[ret], $gp | ||
| 140 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 141 | : | ||
| 142 | : "lr" | ||
| 143 | ), | ||
| 144 | .powerpc, .powerpcle => asm volatile ( | ||
| 145 | \\ .weak _DYNAMIC | ||
| 146 | \\ .hidden _DYNAMIC | ||
| 147 | \\ bl 1f | ||
| 148 | \\ .long _DYNAMIC - . | ||
| 149 | \\ 1: | ||
| 150 | \\ mflr %[ret] | ||
| 151 | \\ lwz 4, 0(%[ret]) | ||
| 152 | \\ add %[ret], 4, %[ret] | ||
| 153 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 154 | : | ||
| 155 | : "lr", "r4" | ||
| 156 | ), | ||
| 157 | .powerpc64, .powerpc64le => asm volatile ( | ||
| 158 | \\ .weak _DYNAMIC | ||
| 159 | \\ .hidden _DYNAMIC | ||
| 160 | \\ bl 1f | ||
| 161 | \\ .quad _DYNAMIC - . | ||
| 162 | \\ 1: | ||
| 163 | \\ mflr %[ret] | ||
| 164 | \\ ld 4, 0(%[ret]) | ||
| 165 | \\ add %[ret], 4, %[ret] | ||
| 166 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 167 | : | ||
| 168 | : "lr", "r4" | ||
| 169 | ), | ||
| 170 | .riscv32, .riscv64 => asm volatile ( | ||
| 171 | \\ .weak _DYNAMIC | ||
| 172 | \\ .hidden _DYNAMIC | ||
| 173 | \\ lla %[ret], _DYNAMIC | ||
| 174 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 175 | ), | ||
| 176 | .s390x => asm volatile ( | ||
| 177 | \\ .weak _DYNAMIC | ||
| 178 | \\ .hidden _DYNAMIC | ||
| 179 | \\ larl %[ret], 1f | ||
| 180 | \\ ag %[ret], 0(%[ret]) | ||
| 181 | \\ jg 2f | ||
| 182 | \\ 1: .quad _DYNAMIC - . | ||
| 183 | \\ 2: | ||
| 184 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 185 | ), | ||
| 186 | // The compiler does not necessarily have any obligation to load the `l7` register (pointing | ||
| 187 | // to the GOT), so do it ourselves just in case. | ||
| 188 | .sparc, .sparc64 => asm volatile ( | ||
| 189 | \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7 | ||
| 190 | \\ call 1f | ||
| 191 | \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7 | ||
| 192 | \\ 1: | ||
| 193 | \\ add %%l7, %%o7, %[ret] | ||
| 194 | : [ret] "=r" (-> [*]elf.Dyn), | ||
| 195 | ), | ||
| 196 | else => { | ||
| 197 | @compileError("PIE startup is not yet supported for this target!"); | ||
| 198 | }, | ||
| 199 | }; | ||
| 200 | } | ||
| 201 | |||
| 202 | pub fn relocate(phdrs: []elf.Phdr) void { | ||
| 203 | @setRuntimeSafety(false); | ||
| 204 | @disableInstrumentation(); | ||
| 205 | |||
| 206 | const dynv = getDynamicSymbol(); | ||
| 207 | |||
| 208 | // Recover the delta applied by the loader by comparing the effective and | ||
| 209 | // the theoretical load addresses for the `_DYNAMIC` symbol. | ||
| 210 | const base_addr = base: { | ||
| 211 | for (phdrs) |*phdr| { | ||
| 212 | if (phdr.p_type != elf.PT_DYNAMIC) continue; | ||
| 213 | break :base @intFromPtr(dynv) - phdr.p_vaddr; | ||
| 214 | } | ||
| 215 | // This is not supposed to happen for well-formed binaries. | ||
| 216 | @trap(); | ||
| 217 | }; | ||
| 218 | |||
| 219 | var sorted_dynv: [elf.DT_NUM]elf.Addr = undefined; | ||
| 220 | |||
| 221 | // Zero-initialized this way to prevent the compiler from turning this into | ||
| 222 | // `memcpy` or `memset` calls (which can require relocations). | ||
| 223 | for (&sorted_dynv) |*dyn| { | ||
| 224 | const pdyn: *volatile elf.Addr = @ptrCast(dyn); | ||
| 225 | pdyn.* = 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | { | ||
| 229 | // `dynv` has no defined order. Fix that. | ||
| 230 | var i: usize = 0; | ||
| 231 | while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { | ||
| 232 | if (dynv[i].d_tag < elf.DT_NUM) sorted_dynv[@bitCast(dynv[i].d_tag)] = dynv[i].d_val; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | // Deal with the GOT relocations that MIPS uses first. | ||
| 237 | if (builtin.cpu.arch.isMIPS()) { | ||
| 238 | const count: elf.Addr = blk: { | ||
| 239 | // This is an architecture-specific tag, so not part of `sorted_dynv`. | ||
| 240 | var i: usize = 0; | ||
| 241 | while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { | ||
| 242 | if (dynv[i].d_tag == elf.DT_MIPS_LOCAL_GOTNO) break :blk dynv[i].d_val; | ||
| 243 | } | ||
| 244 | |||
| 245 | break :blk 0; | ||
| 246 | }; | ||
| 247 | |||
| 248 | const got: [*]usize = @ptrFromInt(base_addr + sorted_dynv[elf.DT_PLTGOT]); | ||
| 249 | |||
| 250 | for (0..count) |i| { | ||
| 251 | got[i] += base_addr; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | // Apply normal relocations. | ||
| 256 | |||
| 257 | const rel = sorted_dynv[elf.DT_REL]; | ||
| 258 | if (rel != 0) { | ||
| 259 | const rels = @call(.always_inline, std.mem.bytesAsSlice, .{ | ||
| 260 | elf.Rel, | ||
| 261 | @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]], | ||
| 262 | }); | ||
| 263 | for (rels) |r| { | ||
| 264 | if (r.r_type() != R_RELATIVE) continue; | ||
| 265 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | const rela = sorted_dynv[elf.DT_RELA]; | ||
| 270 | if (rela != 0) { | ||
| 271 | const relas = @call(.always_inline, std.mem.bytesAsSlice, .{ | ||
| 272 | elf.Rela, | ||
| 273 | @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]], | ||
| 274 | }); | ||
| 275 | for (relas) |r| { | ||
| 276 | if (r.r_type() != R_RELATIVE) continue; | ||
| 277 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | const relr = sorted_dynv[elf.DT_RELR]; | ||
| 282 | if (relr != 0) { | ||
| 283 | const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{ | ||
| 284 | elf.Relr, | ||
| 285 | @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]], | ||
| 286 | }); | ||
| 287 | var current: [*]usize = undefined; | ||
| 288 | for (relrs) |r| { | ||
| 289 | if ((r & 1) == 0) { | ||
| 290 | current = @ptrFromInt(base_addr + r); | ||
| 291 | current[0] += base_addr; | ||
| 292 | current += 1; | ||
| 293 | } else { | ||
| 294 | // Skip the first bit; there are 63 locations in the bitmap. | ||
| 295 | var i: if (@sizeOf(usize) == 8) u6 else u5 = 1; | ||
| 296 | while (i < @bitSizeOf(elf.Relr)) : (i += 1) { | ||
| 297 | if (((r >> i) & 1) != 0) current[i] += base_addr; | ||
| 298 | } | ||
| 299 | |||
| 300 | current += @bitSizeOf(elf.Relr) - 1; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | } | ||
| 304 | } | ||
lib/std/start.zig+38-38| ... | @@ -325,7 +325,7 @@ fn _start() callconv(.naked) noreturn { | ... | @@ -325,7 +325,7 @@ fn _start() callconv(.naked) noreturn { |
| 325 | , | 325 | , |
| 326 | .csky => | 326 | .csky => |
| 327 | // The CSKY ABI assumes that `gb` is set to the address of the GOT in order for | 327 | // The CSKY ABI assumes that `gb` is set to the address of the GOT in order for |
| 328 | // position-independent code to work. We depend on this in `std.os.linux.pie` to locate | 328 | // position-independent code to work. We depend on this in `std.pie` to locate |
| 329 | // `_DYNAMIC` as well. | 329 | // `_DYNAMIC` as well. |
| 330 | // r8 = FP | 330 | // r8 = FP |
| 331 | \\ grs t0, 1f | 331 | \\ grs t0, 1f |
| ... | @@ -514,33 +514,33 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { | ... | @@ -514,33 +514,33 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { |
| 514 | while (envp_optional[envp_count]) |_| : (envp_count += 1) {} | 514 | while (envp_optional[envp_count]) |_| : (envp_count += 1) {} |
| 515 | const envp = @as([*][*:0]u8, @ptrCast(envp_optional))[0..envp_count]; | 515 | const envp = @as([*][*:0]u8, @ptrCast(envp_optional))[0..envp_count]; |
| 516 | 516 | ||
| 517 | if (native_os == .linux) { | 517 | // Find the beginning of the auxiliary vector |
| 518 | // Find the beginning of the auxiliary vector | 518 | const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1)); |
| 519 | const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1)); | 519 | |
| 520 | 520 | var at_hwcap: usize = 0; | |
| 521 | var at_hwcap: usize = 0; | 521 | const phdrs = init: { |
| 522 | const phdrs = init: { | 522 | var i: usize = 0; |
| 523 | var i: usize = 0; | 523 | var at_phdr: usize = 0; |
| 524 | var at_phdr: usize = 0; | 524 | var at_phnum: usize = 0; |
| 525 | var at_phnum: usize = 0; | 525 | while (auxv[i].a_type != elf.AT_NULL) : (i += 1) { |
| 526 | while (auxv[i].a_type != elf.AT_NULL) : (i += 1) { | 526 | switch (auxv[i].a_type) { |
| 527 | switch (auxv[i].a_type) { | 527 | elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, |
| 528 | elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, | 528 | elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, |
| 529 | elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, | 529 | elf.AT_HWCAP => at_hwcap = auxv[i].a_un.a_val, |
| 530 | elf.AT_HWCAP => at_hwcap = auxv[i].a_un.a_val, | 530 | else => continue, |
| 531 | else => continue, | ||
| 532 | } | ||
| 533 | } | 531 | } |
| 534 | break :init @as([*]elf.Phdr, @ptrFromInt(at_phdr))[0..at_phnum]; | ||
| 535 | }; | ||
| 536 | |||
| 537 | // Apply the initial relocations as early as possible in the startup process. We cannot | ||
| 538 | // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet, | ||
| 539 | // so this must be fully inlined. | ||
| 540 | if (builtin.position_independent_executable) { | ||
| 541 | @call(.always_inline, std.os.linux.pie.relocate, .{phdrs}); | ||
| 542 | } | 532 | } |
| 533 | break :init @as([*]elf.Phdr, @ptrFromInt(at_phdr))[0..at_phnum]; | ||
| 534 | }; | ||
| 535 | |||
| 536 | // Apply the initial relocations as early as possible in the startup process. We cannot | ||
| 537 | // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet, | ||
| 538 | // so this must be fully inlined. | ||
| 539 | if (builtin.position_independent_executable) { | ||
| 540 | @call(.always_inline, std.pie.relocate, .{phdrs}); | ||
| 541 | } | ||
| 543 | 542 | ||
| 543 | if (native_os == .linux) { | ||
| 544 | // This must be done after PIE relocations have been applied or we may crash | 544 | // This must be done after PIE relocations have been applied or we may crash |
| 545 | // while trying to access the global variable (happens on MIPS at least). | 545 | // while trying to access the global variable (happens on MIPS at least). |
| 546 | std.os.linux.elf_aux_maybe = auxv; | 546 | std.os.linux.elf_aux_maybe = auxv; |
| ... | @@ -567,20 +567,20 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { | ... | @@ -567,20 +567,20 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { |
| 567 | // Here we look for the stack size in our program headers and use setrlimit | 567 | // Here we look for the stack size in our program headers and use setrlimit |
| 568 | // to ask for more stack space. | 568 | // to ask for more stack space. |
| 569 | expandStackSize(phdrs); | 569 | expandStackSize(phdrs); |
| 570 | } | ||
| 570 | 571 | ||
| 571 | const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{ | 572 | const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{ |
| 572 | .name = "__init_array_start", | 573 | .name = "__init_array_start", |
| 573 | .linkage = .weak, | 574 | .linkage = .weak, |
| 574 | }); | 575 | }); |
| 575 | const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{ | 576 | const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{ |
| 576 | .name = "__init_array_end", | 577 | .name = "__init_array_end", |
| 577 | .linkage = .weak, | 578 | .linkage = .weak, |
| 578 | }); | 579 | }); |
| 579 | if (opt_init_array_start) |init_array_start| { | 580 | if (opt_init_array_start) |init_array_start| { |
| 580 | const init_array_end = opt_init_array_end.?; | 581 | const init_array_end = opt_init_array_end.?; |
| 581 | const slice = init_array_start[0 .. init_array_end - init_array_start]; | 582 | const slice = init_array_start[0 .. init_array_end - init_array_start]; |
| 582 | for (slice) |func| func(); | 583 | for (slice) |func| func(); |
| 583 | } | ||
| 584 | } | 584 | } |
| 585 | 585 | ||
| 586 | std.posix.exit(callMainWithArgs(argc, argv, envp)); | 586 | std.posix.exit(callMainWithArgs(argc, argv, envp)); |
lib/std/std.zig+1| ... | @@ -79,6 +79,7 @@ pub const net = @import("net.zig"); | ... | @@ -79,6 +79,7 @@ pub const net = @import("net.zig"); |
| 79 | pub const os = @import("os.zig"); | 79 | pub const os = @import("os.zig"); |
| 80 | pub const once = @import("once.zig").once; | 80 | pub const once = @import("once.zig").once; |
| 81 | pub const pdb = @import("pdb.zig"); | 81 | pub const pdb = @import("pdb.zig"); |
| 82 | pub const pie = @import("pie.zig"); | ||
| 82 | pub const posix = @import("posix.zig"); | 83 | pub const posix = @import("posix.zig"); |
| 83 | pub const process = @import("process.zig"); | 84 | pub const process = @import("process.zig"); |
| 84 | pub const sort = @import("sort.zig"); | 85 | pub const sort = @import("sort.zig"); |