Function relocate [src]

Prototype

pub fn relocate(phdrs: []elf.Phdr) void

Parameters

phdrs: []elf.Phdr

Source

pub fn relocate(phdrs: []elf.Phdr) void { @setRuntimeSafety(false); @disableInstrumentation(); const dynv = getDynamicSymbol(); // Recover the delta applied by the loader by comparing the effective and // the theoretical load addresses for the `_DYNAMIC` symbol. const base_addr = base: { for (phdrs) |*phdr| { if (phdr.p_type != elf.PT_DYNAMIC) continue; break :base @intFromPtr(dynv) - phdr.p_vaddr; } // This is not supposed to happen for well-formed binaries. @trap(); }; var sorted_dynv: [elf.DT_NUM]elf.Addr = undefined; // Zero-initialized this way to prevent the compiler from turning this into // `memcpy` or `memset` calls (which can require relocations). for (&sorted_dynv) |*dyn| { const pdyn: *volatile elf.Addr = @ptrCast(dyn); pdyn.* = 0; } { // `dynv` has no defined order. Fix that. var i: usize = 0; while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { if (dynv[i].d_tag < elf.DT_NUM) sorted_dynv[@bitCast(dynv[i].d_tag)] = dynv[i].d_val; } } // Deal with the GOT relocations that MIPS uses first. if (builtin.cpu.arch.isMIPS()) { const count: elf.Addr = blk: { // This is an architecture-specific tag, so not part of `sorted_dynv`. var i: usize = 0; while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { if (dynv[i].d_tag == elf.DT_MIPS_LOCAL_GOTNO) break :blk dynv[i].d_val; } break :blk 0; }; const got: [*]usize = @ptrFromInt(base_addr + sorted_dynv[elf.DT_PLTGOT]); for (0..count) |i| { got[i] += base_addr; } } // Apply normal relocations. const rel = sorted_dynv[elf.DT_REL]; if (rel != 0) { const rels = @call(.always_inline, std.mem.bytesAsSlice, .{ elf.Rel, @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]], }); for (rels) |r| { if (r.r_type() != R_RELATIVE) continue; @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; } } const rela = sorted_dynv[elf.DT_RELA]; if (rela != 0) { const relas = @call(.always_inline, std.mem.bytesAsSlice, .{ elf.Rela, @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]], }); for (relas) |r| { if (r.r_type() != R_RELATIVE) continue; @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); } } const relr = sorted_dynv[elf.DT_RELR]; if (relr != 0) { const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{ elf.Relr, @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]], }); var current: [*]usize = undefined; for (relrs) |r| { if ((r & 1) == 0) { current = @ptrFromInt(base_addr + r); current[0] += base_addr; current += 1; } else { // Skip the first bit; there are 63 locations in the bitmap. var i: if (@sizeOf(usize) == 8) u6 else u5 = 1; while (i < @bitSizeOf(elf.Relr)) : (i += 1) { if (((r >> i) & 1) != 0) current[i] += base_addr; } current += @bitSizeOf(elf.Relr) - 1; } } } }