authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-01 00:57:10-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-01 00:57:10-07:00
log9c22a6b3ade561b4009020547980fcf2d76a9f57
tree062ab284dc571989f7320b893596f237fa1b1181
parent63aa85e7afb37d0b2b5c48309ef1a88d8fd444b5
parent2e719f32397c1ec87a9f5a5b6947dbc553471707
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20823 from alexrp/start-pie-mips-ppc

`std.os.linux.start_pie`: Add mips and powerpc support

1 files changed, 105 insertions(+), 20 deletions(-)

lib/std/os/linux/start_pie.zig+105-20
......@@ -12,6 +12,8 @@ const R_CSKY_RELATIVE = 9;
1212const R_HEXAGON_RELATIVE = 35;
1313const R_LARCH_RELATIVE = 3;
1414const R_68K_RELATIVE = 22;
15const R_MIPS_RELATIVE = 128;
16const R_PPC_RELATIVE = 22;
1517const R_RISCV_RELATIVE = 3;
1618const R_390_RELATIVE = 12;
1719const R_SPARC_RELATIVE = 22;
......@@ -26,6 +28,8 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
2628 .hexagon => R_HEXAGON_RELATIVE,
2729 .loongarch32, .loongarch64 => R_LARCH_RELATIVE,
2830 .m68k => R_68K_RELATIVE,
31 .mips, .mipsel, .mips64, .mips64el => R_MIPS_RELATIVE,
32 .powerpc, .powerpcle, .powerpc64, .powerpc64le => R_PPC_RELATIVE,
2933 .riscv32, .riscv64 => R_RISCV_RELATIVE,
3034 .s390x => R_390_RELATIVE,
3135 else => @compileError("Missing R_RELATIVE definition for this target"),
......@@ -34,7 +38,7 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
3438// Obtain a pointer to the _DYNAMIC array.
3539// We have to compute its address as a PC-relative quantity not to require a
3640// relocation that, at this point, is not yet applied.
37fn getDynamicSymbol() [*]elf.Dyn {
41inline fn getDynamicSymbol() [*]elf.Dyn {
3842 return switch (builtin.cpu.arch) {
3943 .x86 => asm volatile (
4044 \\ .weak _DYNAMIC
......@@ -111,6 +115,57 @@ fn getDynamicSymbol() [*]elf.Dyn {
111115 \\ lea (%[ret], %%pc), %[ret]
112116 : [ret] "=r" (-> [*]elf.Dyn),
113117 ),
118 .mips, .mipsel => asm volatile (
119 \\ .weak _DYNAMIC
120 \\ .hidden _DYNAMIC
121 \\ bal 1f
122 \\ .gpword _DYNAMIC
123 \\ 1:
124 \\ lw %[ret], 0($ra)
125 \\ addu %[ret], %[ret], $gp
126 : [ret] "=r" (-> [*]elf.Dyn),
127 :
128 : "lr"
129 ),
130 .mips64, .mips64el => asm volatile (
131 \\ .weak _DYNAMIC
132 \\ .hidden _DYNAMIC
133 \\ .balign 8
134 \\ bal 1f
135 \\ .gpdword _DYNAMIC
136 \\ 1:
137 \\ ld %[ret], 0($ra)
138 \\ daddu %[ret], %[ret], $gp
139 : [ret] "=r" (-> [*]elf.Dyn),
140 :
141 : "lr"
142 ),
143 .powerpc, .powerpcle => asm volatile (
144 \\ .weak _DYNAMIC
145 \\ .hidden _DYNAMIC
146 \\ bl 1f
147 \\ .long _DYNAMIC - .
148 \\ 1:
149 \\ mflr %[ret]
150 \\ lwz 4, 0(%[ret])
151 \\ add %[ret], 4, %[ret]
152 : [ret] "=r" (-> [*]elf.Dyn),
153 :
154 : "lr", "r4"
155 ),
156 .powerpc64, .powerpc64le => asm volatile (
157 \\ .weak _DYNAMIC
158 \\ .hidden _DYNAMIC
159 \\ bl 1f
160 \\ .quad _DYNAMIC - .
161 \\ 1:
162 \\ mflr %[ret]
163 \\ ld 4, 0(%[ret])
164 \\ add %[ret], 4, %[ret]
165 : [ret] "=r" (-> [*]elf.Dyn),
166 :
167 : "lr", "r4"
168 ),
114169 .riscv32, .riscv64 => asm volatile (
115170 \\ .weak _DYNAMIC
116171 \\ .hidden _DYNAMIC
......@@ -121,9 +176,9 @@ fn getDynamicSymbol() [*]elf.Dyn {
121176 \\ .weak _DYNAMIC
122177 \\ .hidden _DYNAMIC
123178 \\ larl %[ret], 1f
124 \\ agf %[ret], 0(%[ret])
179 \\ ag %[ret], 0(%[ret])
125180 \\ b 2f
126 \\ 1: .long _DYNAMIC - .
181 \\ 1: .quad _DYNAMIC - .
127182 \\ 2:
128183 : [ret] "=r" (-> [*]elf.Dyn),
129184 ),
......@@ -138,6 +193,7 @@ pub fn relocate(phdrs: []elf.Phdr) void {
138193 @disableInstrumentation();
139194
140195 const dynv = getDynamicSymbol();
196
141197 // Recover the delta applied by the loader by comparing the effective and
142198 // the theoretical load addresses for the `_DYNAMIC` symbol.
143199 const base_addr = base: {
......@@ -149,34 +205,63 @@ pub fn relocate(phdrs: []elf.Phdr) void {
149205 @trap();
150206 };
151207
152 var rel_addr: usize = 0;
153 var rela_addr: usize = 0;
154 var rel_size: usize = 0;
155 var rela_size: usize = 0;
208 var sorted_dynv: [elf.DT_NUM]elf.Addr = undefined;
209
210 // Zero-initialized this way to prevent the compiler from turning this into
211 // `memcpy` or `memset` calls (which can require relocations).
212 for (&sorted_dynv) |*dyn| {
213 const pdyn: *volatile elf.Addr = @ptrCast(dyn);
214 pdyn.* = 0;
215 }
216
156217 {
218 // `dynv` has no defined order. Fix that.
157219 var i: usize = 0;
158220 while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) {
159 switch (dynv[i].d_tag) {
160 elf.DT_REL => rel_addr = base_addr + dynv[i].d_val,
161 elf.DT_RELA => rela_addr = base_addr + dynv[i].d_val,
162 elf.DT_RELSZ => rel_size = dynv[i].d_val,
163 elf.DT_RELASZ => rela_size = dynv[i].d_val,
164 else => {},
221 if (dynv[i].d_tag < elf.DT_NUM) sorted_dynv[@bitCast(dynv[i].d_tag)] = dynv[i].d_val;
222 }
223 }
224
225 // Deal with the GOT relocations that MIPS uses first.
226 if (builtin.cpu.arch.isMIPS()) {
227 const count: elf.Addr = blk: {
228 // This is an architecture-specific tag, so not part of `sorted_dynv`.
229 var i: usize = 0;
230 while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) {
231 if (dynv[i].d_tag == elf.DT_MIPS_LOCAL_GOTNO) break :blk dynv[i].d_val;
165232 }
233
234 break :blk 0;
235 };
236
237 const got: [*]usize = @ptrFromInt(base_addr + sorted_dynv[elf.DT_PLTGOT]);
238
239 for (0..count) |i| {
240 got[i] += base_addr;
166241 }
167242 }
168243
169 // Apply the relocations.
170 if (rel_addr != 0) {
171 const rel = std.mem.bytesAsSlice(elf.Rel, @as([*]u8, @ptrFromInt(rel_addr))[0..rel_size]);
172 for (rel) |r| {
244 // Apply normal relocations.
245
246 const rel = sorted_dynv[elf.DT_REL];
247 if (rel != 0) {
248 const rels = @call(.always_inline, std.mem.bytesAsSlice, .{
249 elf.Rel,
250 @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
251 });
252 for (rels) |r| {
173253 if (r.r_type() != R_RELATIVE) continue;
174254 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;
175255 }
176256 }
177 if (rela_addr != 0) {
178 const rela = std.mem.bytesAsSlice(elf.Rela, @as([*]u8, @ptrFromInt(rela_addr))[0..rela_size]);
179 for (rela) |r| {
257
258 const rela = sorted_dynv[elf.DT_RELA];
259 if (rela != 0) {
260 const relas = @call(.always_inline, std.mem.bytesAsSlice, .{
261 elf.Rela,
262 @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
263 });
264 for (relas) |r| {
180265 if (r.r_type() != R_RELATIVE) continue;
181266 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend));
182267 }