| ... | ... | @@ -12,6 +12,8 @@ const R_CSKY_RELATIVE = 9; |
| 12 | 12 | const R_HEXAGON_RELATIVE = 35; |
| 13 | 13 | const R_LARCH_RELATIVE = 3; |
| 14 | 14 | const R_68K_RELATIVE = 22; |
| 15 | const R_MIPS_RELATIVE = 128; |
| 16 | const R_PPC_RELATIVE = 22; |
| 15 | 17 | const R_RISCV_RELATIVE = 3; |
| 16 | 18 | const R_390_RELATIVE = 12; |
| 17 | 19 | const R_SPARC_RELATIVE = 22; |
| ... | ... | @@ -26,6 +28,8 @@ const R_RELATIVE = switch (builtin.cpu.arch) { |
| 26 | 28 | .hexagon => R_HEXAGON_RELATIVE, |
| 27 | 29 | .loongarch32, .loongarch64 => R_LARCH_RELATIVE, |
| 28 | 30 | .m68k => R_68K_RELATIVE, |
| 31 | .mips, .mipsel, .mips64, .mips64el => R_MIPS_RELATIVE, |
| 32 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => R_PPC_RELATIVE, |
| 29 | 33 | .riscv32, .riscv64 => R_RISCV_RELATIVE, |
| 30 | 34 | .s390x => R_390_RELATIVE, |
| 31 | 35 | else => @compileError("Missing R_RELATIVE definition for this target"), |
| ... | ... | @@ -34,7 +38,7 @@ const R_RELATIVE = switch (builtin.cpu.arch) { |
| 34 | 38 | // Obtain a pointer to the _DYNAMIC array. |
| 35 | 39 | // We have to compute its address as a PC-relative quantity not to require a |
| 36 | 40 | // relocation that, at this point, is not yet applied. |
| 37 | | fn getDynamicSymbol() [*]elf.Dyn { |
| 41 | inline fn getDynamicSymbol() [*]elf.Dyn { |
| 38 | 42 | return switch (builtin.cpu.arch) { |
| 39 | 43 | .x86 => asm volatile ( |
| 40 | 44 | \\ .weak _DYNAMIC |
| ... | ... | @@ -111,6 +115,57 @@ fn getDynamicSymbol() [*]elf.Dyn { |
| 111 | 115 | \\ lea (%[ret], %%pc), %[ret] |
| 112 | 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 | 169 | .riscv32, .riscv64 => asm volatile ( |
| 115 | 170 | \\ .weak _DYNAMIC |
| 116 | 171 | \\ .hidden _DYNAMIC |
| ... | ... | @@ -121,9 +176,9 @@ fn getDynamicSymbol() [*]elf.Dyn { |
| 121 | 176 | \\ .weak _DYNAMIC |
| 122 | 177 | \\ .hidden _DYNAMIC |
| 123 | 178 | \\ larl %[ret], 1f |
| 124 | | \\ agf %[ret], 0(%[ret]) |
| 179 | \\ ag %[ret], 0(%[ret]) |
| 125 | 180 | \\ b 2f |
| 126 | | \\ 1: .long _DYNAMIC - . |
| 181 | \\ 1: .quad _DYNAMIC - . |
| 127 | 182 | \\ 2: |
| 128 | 183 | : [ret] "=r" (-> [*]elf.Dyn), |
| 129 | 184 | ), |
| ... | ... | @@ -138,6 +193,7 @@ pub fn relocate(phdrs: []elf.Phdr) void { |
| 138 | 193 | @disableInstrumentation(); |
| 139 | 194 | |
| 140 | 195 | const dynv = getDynamicSymbol(); |
| 196 | |
| 141 | 197 | // Recover the delta applied by the loader by comparing the effective and |
| 142 | 198 | // the theoretical load addresses for the `_DYNAMIC` symbol. |
| 143 | 199 | const base_addr = base: { |
| ... | ... | @@ -149,34 +205,63 @@ pub fn relocate(phdrs: []elf.Phdr) void { |
| 149 | 205 | @trap(); |
| 150 | 206 | }; |
| 151 | 207 | |
| 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 | |
| 156 | 217 | { |
| 218 | // `dynv` has no defined order. Fix that. |
| 157 | 219 | var i: usize = 0; |
| 158 | 220 | 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; |
| 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. |
| 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| { |
| 173 | 253 | if (r.r_type() != R_RELATIVE) continue; |
| 174 | 254 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; |
| 175 | 255 | } |
| 176 | 256 | } |
| 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| { |
| 180 | 265 | if (r.r_type() != R_RELATIVE) continue; |
| 181 | 266 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); |
| 182 | 267 | } |