| ... | @@ -193,6 +193,7 @@ pub fn relocate(phdrs: []elf.Phdr) void { | ... | @@ -193,6 +193,7 @@ pub fn relocate(phdrs: []elf.Phdr) void { |
| 193 | @disableInstrumentation(); | 193 | @disableInstrumentation(); |
| 194 | | 194 | |
| 195 | const dynv = getDynamicSymbol(); | 195 | const dynv = getDynamicSymbol(); |
| | 196 | |
| 196 | // 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 |
| 197 | // the theoretical load addresses for the `_DYNAMIC` symbol. | 198 | // the theoretical load addresses for the `_DYNAMIC` symbol. |
| 198 | const base_addr = base: { | 199 | const base_addr = base: { |
| ... | @@ -204,34 +205,45 @@ pub fn relocate(phdrs: []elf.Phdr) void { | ... | @@ -204,34 +205,45 @@ pub fn relocate(phdrs: []elf.Phdr) void { |
| 204 | @trap(); | 205 | @trap(); |
| 205 | }; | 206 | }; |
| 206 | | 207 | |
| 207 | var rel_addr: usize = 0; | 208 | var sorted_dynv: [elf.DT_NUM]elf.Addr = undefined; |
| 208 | var rela_addr: usize = 0; | 209 | |
| 209 | var rel_size: usize = 0; | 210 | // Zero-initialized this way to prevent the compiler from turning this into |
| 210 | 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 | |
| 211 | { | 217 | { |
| | 218 | // `dynv` has no defined order. Fix that. |
| 212 | var i: usize = 0; | 219 | var i: usize = 0; |
| 213 | while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { | 220 | while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { |
| 214 | 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; |
| 215 | elf.DT_REL => rel_addr = base_addr + dynv[i].d_val, | | |
| 216 | elf.DT_RELA => rela_addr = base_addr + dynv[i].d_val, | | |
| 217 | elf.DT_RELSZ => rel_size = dynv[i].d_val, | | |
| 218 | elf.DT_RELASZ => rela_size = dynv[i].d_val, | | |
| 219 | else => {}, | | |
| 220 | } | | |
| 221 | } | 222 | } |
| 222 | } | 223 | } |
| 223 | | 224 | |
| 224 | // Apply the relocations. | 225 | |
| 225 | if (rel_addr != 0) { | 226 | // Apply normal relocations. |
| 226 | const rel = std.mem.bytesAsSlice(elf.Rel, @as([*]u8, @ptrFromInt(rel_addr))[0..rel_size]); | 227 | |
| 227 | for (rel) |r| { | 228 | const rel = sorted_dynv[elf.DT_REL]; |
| | 229 | if (rel != 0) { |
| | 230 | const rels = @call(.always_inline, std.mem.bytesAsSlice, .{ |
| | 231 | elf.Rel, |
| | 232 | @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]], |
| | 233 | }); |
| | 234 | for (rels) |r| { |
| 228 | if (r.r_type() != R_RELATIVE) continue; | 235 | if (r.r_type() != R_RELATIVE) continue; |
| 229 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; | 236 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; |
| 230 | } | 237 | } |
| 231 | } | 238 | } |
| 232 | if (rela_addr != 0) { | 239 | |
| 233 | const rela = std.mem.bytesAsSlice(elf.Rela, @as([*]u8, @ptrFromInt(rela_addr))[0..rela_size]); | 240 | const rela = sorted_dynv[elf.DT_RELA]; |
| 234 | for (rela) |r| { | 241 | if (rela != 0) { |
| | 242 | const relas = @call(.always_inline, std.mem.bytesAsSlice, .{ |
| | 243 | elf.Rela, |
| | 244 | @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]], |
| | 245 | }); |
| | 246 | for (relas) |r| { |
| 235 | if (r.r_type() != R_RELATIVE) continue; | 247 | if (r.r_type() != R_RELATIVE) continue; |
| 236 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); | 248 | @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); |
| 237 | } | 249 | } |