| ... | @@ -12,6 +12,8 @@ const R_CSKY_RELATIVE = 9; | ... | @@ -12,6 +12,8 @@ const R_CSKY_RELATIVE = 9; |
| 12 | const R_HEXAGON_RELATIVE = 35; | 12 | const R_HEXAGON_RELATIVE = 35; |
| 13 | const R_LARCH_RELATIVE = 3; | 13 | const R_LARCH_RELATIVE = 3; |
| 14 | const R_68K_RELATIVE = 22; | 14 | const R_68K_RELATIVE = 22; |
| | 15 | const R_MIPS_RELATIVE = 128; |
| | 16 | const R_PPC_RELATIVE = 22; |
| 15 | const R_RISCV_RELATIVE = 3; | 17 | const R_RISCV_RELATIVE = 3; |
| 16 | const R_390_RELATIVE = 12; | 18 | const R_390_RELATIVE = 12; |
| 17 | const R_SPARC_RELATIVE = 22; | 19 | const R_SPARC_RELATIVE = 22; |
| ... | @@ -26,6 +28,8 @@ const R_RELATIVE = switch (builtin.cpu.arch) { | ... | @@ -26,6 +28,8 @@ const R_RELATIVE = switch (builtin.cpu.arch) { |
| 26 | .hexagon => R_HEXAGON_RELATIVE, | 28 | .hexagon => R_HEXAGON_RELATIVE, |
| 27 | .loongarch32, .loongarch64 => R_LARCH_RELATIVE, | 29 | .loongarch32, .loongarch64 => R_LARCH_RELATIVE, |
| 28 | .m68k => R_68K_RELATIVE, | 30 | .m68k => R_68K_RELATIVE, |
| | 31 | .mips, .mipsel, .mips64, .mips64el => R_MIPS_RELATIVE, |
| | 32 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => R_PPC_RELATIVE, |
| 29 | .riscv32, .riscv64 => R_RISCV_RELATIVE, | 33 | .riscv32, .riscv64 => R_RISCV_RELATIVE, |
| 30 | .s390x => R_390_RELATIVE, | 34 | .s390x => R_390_RELATIVE, |
| 31 | else => @compileError("Missing R_RELATIVE definition for this target"), | 35 | else => @compileError("Missing R_RELATIVE definition for this target"), |
| ... | @@ -34,7 +38,7 @@ const R_RELATIVE = switch (builtin.cpu.arch) { | ... | @@ -34,7 +38,7 @@ const R_RELATIVE = switch (builtin.cpu.arch) { |
| 34 | // Obtain a pointer to the _DYNAMIC array. | 38 | // Obtain a pointer to the _DYNAMIC array. |
| 35 | // We have to compute its address as a PC-relative quantity not to require a | 39 | // We have to compute its address as a PC-relative quantity not to require a |
| 36 | // relocation that, at this point, is not yet applied. | 40 | // relocation that, at this point, is not yet applied. |
| 37 | fn getDynamicSymbol() [*]elf.Dyn { | 41 | inline fn getDynamicSymbol() [*]elf.Dyn { |
| 38 | return switch (builtin.cpu.arch) { | 42 | return switch (builtin.cpu.arch) { |
| 39 | .x86 => asm volatile ( | 43 | .x86 => asm volatile ( |
| 40 | \\ .weak _DYNAMIC | 44 | \\ .weak _DYNAMIC |
| ... | @@ -111,6 +115,57 @@ fn getDynamicSymbol() [*]elf.Dyn { | ... | @@ -111,6 +115,57 @@ fn getDynamicSymbol() [*]elf.Dyn { |
| 111 | \\ lea (%[ret], %%pc), %[ret] | 115 | \\ lea (%[ret], %%pc), %[ret] |
| 112 | : [ret] "=r" (-> [*]elf.Dyn), | 116 | : [ret] "=r" (-> [*]elf.Dyn), |
| 113 | ), | 117 | ), |
| | 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 | ), |
| 114 | .riscv32, .riscv64 => asm volatile ( | 169 | .riscv32, .riscv64 => asm volatile ( |
| 115 | \\ .weak _DYNAMIC | 170 | \\ .weak _DYNAMIC |
| 116 | \\ .hidden _DYNAMIC | 171 | \\ .hidden _DYNAMIC |
| ... | @@ -121,9 +176,9 @@ fn getDynamicSymbol() [*]elf.Dyn { | ... | @@ -121,9 +176,9 @@ fn getDynamicSymbol() [*]elf.Dyn { |
| 121 | \\ .weak _DYNAMIC | 176 | \\ .weak _DYNAMIC |
| 122 | \\ .hidden _DYNAMIC | 177 | \\ .hidden _DYNAMIC |
| 123 | \\ larl %[ret], 1f | 178 | \\ larl %[ret], 1f |
| 124 | \\ agf %[ret], 0(%[ret]) | 179 | \\ ag %[ret], 0(%[ret]) |
| 125 | \\ b 2f | 180 | \\ b 2f |
| 126 | \\ 1: .long _DYNAMIC - . | 181 | \\ 1: .quad _DYNAMIC - . |
| 127 | \\ 2: | 182 | \\ 2: |
| 128 | : [ret] "=r" (-> [*]elf.Dyn), | 183 | : [ret] "=r" (-> [*]elf.Dyn), |
| 129 | ), | 184 | ), |
| ... | @@ -138,6 +193,7 @@ pub fn relocate(phdrs: []elf.Phdr) void { | ... | @@ -138,6 +193,7 @@ pub fn relocate(phdrs: []elf.Phdr) void { |
| 138 | @disableInstrumentation(); | 193 | @disableInstrumentation(); |
| 139 | | 194 | |
| 140 | const dynv = getDynamicSymbol(); | 195 | const dynv = getDynamicSymbol(); |
| | 196 | |
| 141 | // Recover the delta applied by the loader by comparing the effective and | 197 | // Recover the delta applied by the loader by comparing the effective and |
| 142 | // the theoretical load addresses for the `_DYNAMIC` symbol. | 198 | // the theoretical load addresses for the `_DYNAMIC` symbol. |
| 143 | const base_addr = base: { | 199 | const base_addr = base: { |
| ... | @@ -149,34 +205,63 @@ pub fn relocate(phdrs: []elf.Phdr) void { | ... | @@ -149,34 +205,63 @@ pub fn relocate(phdrs: []elf.Phdr) void { |
| 149 | @trap(); | 205 | @trap(); |
| 150 | }; | 206 | }; |
| 151 | | 207 | |
| 152 | var rel_addr: usize = 0; | 208 | var sorted_dynv: [elf.DT_NUM]elf.Addr = undefined; |
| 153 | var rela_addr: usize = 0; | 209 | |
| 154 | var rel_size: usize = 0; | 210 | // Zero-initialized this way to prevent the compiler from turning this into |
| 155 | var rela_size: usize = 0; | 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 | |
| 156 | { | 217 | { |
| | 218 | // `dynv` has no defined order. Fix that. |
| 157 | var i: usize = 0; | 219 | var i: usize = 0; |
| 158 | while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { | 220 | while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { |
| 159 | switch (dynv[i].d_tag) { | 221 | if (dynv[i].d_tag < elf.DT_NUM) sorted_dynv[@bitCast(dynv[i].d_tag)] = dynv[i].d_val; |
| 160 | elf.DT_REL => rel_addr = base_addr + dynv[i].d_val, | 222 | } |
| 161 | elf.DT_RELA => rela_addr = base_addr + dynv[i].d_val, | 223 | } |
| 162 | elf.DT_RELSZ => rel_size = dynv[i].d_val, | 224 | |
| 163 | elf.DT_RELASZ => rela_size = dynv[i].d_val, | 225 | // Deal with the GOT relocations that MIPS uses first. |
| 164 | else => {}, | 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; |
| 165 | } | 232 | } |
| | 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; |
| 166 | } | 241 | } |
| 167 | } | 242 | } |
| 168 | | 243 | |
| 169 | // Apply the relocations. | 244 | // Apply normal relocations. |
| 170 | if (rel_addr != 0) { | 245 | |
| 171 | const rel = std.mem.bytesAsSlice(elf.Rel, @as([*]u8, @ptrFromInt(rel_addr))[0..rel_size]); | 246 | const rel = sorted_dynv[elf.DT_REL]; |
| 172 | for (rel) |r| { | 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| { |
| 173 | if (r.r_type() != R_RELATIVE) continue; | 253 | if (r.r_type() != R_RELATIVE) continue; |
| 174 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; | 254 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; |
| 175 | } | 255 | } |
| 176 | } | 256 | } |
| 177 | if (rela_addr != 0) { | 257 | |
| 178 | const rela = std.mem.bytesAsSlice(elf.Rela, @as([*]u8, @ptrFromInt(rela_addr))[0..rela_size]); | 258 | const rela = sorted_dynv[elf.DT_RELA]; |
| 179 | for (rela) |r| { | 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| { |
| 180 | if (r.r_type() != R_RELATIVE) continue; | 265 | if (r.r_type() != R_RELATIVE) continue; |
| 181 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); | 266 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); |
| 182 | } | 267 | } |