authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-05-18 02:01:37+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-05-18 17:14:09+02:00
log74a3ae492797b1b2cf1936f0c91560585efdf6c6
treeba520c805a8f89d85dbe51dafd4c405bf2fa65b6
parent8e72a25285b5e782ee44828b6d1904d91fb16a29

start: Don't artificially limit some posixCallMainAndExit() logic to Linux.

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;
115115pub const getcontext = arch_bits.getcontext;
116116
117117pub const tls = @import("linux/tls.zig");
118pub const pie = @import("linux/pie.zig");
119118pub const BPF = @import("linux/bpf.zig");
120119pub const IOCTL = @import("linux/ioctl.zig");
121120pub const SECCOMP = @import("linux/seccomp.zig");
lib/std/os/linux/pie.zig deleted-304
......@@ -1,304 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const elf = std.elf;
4const assert = std.debug.assert;
5
6const R_AMD64_RELATIVE = 8;
7const R_386_RELATIVE = 8;
8const R_ARC_RELATIVE = 56;
9const R_ARM_RELATIVE = 23;
10const R_AARCH64_RELATIVE = 1027;
11const R_CSKY_RELATIVE = 9;
12const R_HEXAGON_RELATIVE = 35;
13const R_LARCH_RELATIVE = 3;
14const R_68K_RELATIVE = 22;
15const R_MIPS_RELATIVE = 128;
16const R_PPC_RELATIVE = 22;
17const R_RISCV_RELATIVE = 3;
18const R_390_RELATIVE = 12;
19const R_SPARC_RELATIVE = 22;
20
21const 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.
42inline 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
202pub 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 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const elf = std.elf;
4const assert = std.debug.assert;
5
6const R_AMD64_RELATIVE = 8;
7const R_386_RELATIVE = 8;
8const R_ARC_RELATIVE = 56;
9const R_ARM_RELATIVE = 23;
10const R_AARCH64_RELATIVE = 1027;
11const R_CSKY_RELATIVE = 9;
12const R_HEXAGON_RELATIVE = 35;
13const R_LARCH_RELATIVE = 3;
14const R_68K_RELATIVE = 22;
15const R_MIPS_RELATIVE = 128;
16const R_PPC_RELATIVE = 22;
17const R_RISCV_RELATIVE = 3;
18const R_390_RELATIVE = 12;
19const R_SPARC_RELATIVE = 22;
20
21const 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.
42inline 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
202pub 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 {
325325 ,
326326 .csky =>
327327 // 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
329329 // `_DYNAMIC` as well.
330330 // r8 = FP
331331 \\ grs t0, 1f
......@@ -514,33 +514,33 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
514514 while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
515515 const envp = @as([*][*:0]u8, @ptrCast(envp_optional))[0..envp_count];
516516
517 if (native_os == .linux) {
518 // Find the beginning of the auxiliary vector
519 const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1));
520
521 var at_hwcap: usize = 0;
522 const phdrs = init: {
523 var i: usize = 0;
524 var at_phdr: usize = 0;
525 var at_phnum: usize = 0;
526 while (auxv[i].a_type != elf.AT_NULL) : (i += 1) {
527 switch (auxv[i].a_type) {
528 elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val,
529 elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val,
530 elf.AT_HWCAP => at_hwcap = auxv[i].a_un.a_val,
531 else => continue,
532 }
517 // Find the beginning of the auxiliary vector
518 const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1));
519
520 var at_hwcap: usize = 0;
521 const phdrs = init: {
522 var i: usize = 0;
523 var at_phdr: usize = 0;
524 var at_phnum: usize = 0;
525 while (auxv[i].a_type != elf.AT_NULL) : (i += 1) {
526 switch (auxv[i].a_type) {
527 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_HWCAP => at_hwcap = auxv[i].a_un.a_val,
530 else => continue,
533531 }
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});
542532 }
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 }
543542
543 if (native_os == .linux) {
544544 // This must be done after PIE relocations have been applied or we may crash
545545 // while trying to access the global variable (happens on MIPS at least).
546546 std.os.linux.elf_aux_maybe = auxv;
......@@ -567,20 +567,20 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
567567 // Here we look for the stack size in our program headers and use setrlimit
568568 // to ask for more stack space.
569569 expandStackSize(phdrs);
570 }
570571
571 const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{
572 .name = "__init_array_start",
573 .linkage = .weak,
574 });
575 const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{
576 .name = "__init_array_end",
577 .linkage = .weak,
578 });
579 if (opt_init_array_start) |init_array_start| {
580 const init_array_end = opt_init_array_end.?;
581 const slice = init_array_start[0 .. init_array_end - init_array_start];
582 for (slice) |func| func();
583 }
572 const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{
573 .name = "__init_array_start",
574 .linkage = .weak,
575 });
576 const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{
577 .name = "__init_array_end",
578 .linkage = .weak,
579 });
580 if (opt_init_array_start) |init_array_start| {
581 const init_array_end = opt_init_array_end.?;
582 const slice = init_array_start[0 .. init_array_end - init_array_start];
583 for (slice) |func| func();
584584 }
585585
586586 std.posix.exit(callMainWithArgs(argc, argv, envp));
lib/std/std.zig+1
......@@ -79,6 +79,7 @@ pub const net = @import("net.zig");
7979pub const os = @import("os.zig");
8080pub const once = @import("once.zig").once;
8181pub const pdb = @import("pdb.zig");
82pub const pie = @import("pie.zig");
8283pub const posix = @import("posix.zig");
8384pub const process = @import("process.zig");
8485pub const sort = @import("sort.zig");