factor out patching an elf from loading it to prepare vdso
This commit is contained in:
38
src/main.zig
38
src/main.zig
@@ -71,6 +71,7 @@ pub fn main() !void {
|
|||||||
const base = try loadStaticElf(ehdr, &file_reader);
|
const base = try loadStaticElf(ehdr, &file_reader);
|
||||||
const entry = ehdr.entry + if (ehdr.type == .DYN) base else 0;
|
const entry = ehdr.entry + if (ehdr.type == .DYN) base else 0;
|
||||||
log.info("Executable loaded: base=0x{x}, entry=0x{x}", .{ base, entry });
|
log.info("Executable loaded: base=0x{x}, entry=0x{x}", .{ base, entry });
|
||||||
|
try patchLoadedElf(base);
|
||||||
|
|
||||||
// Check for dynamic linker
|
// Check for dynamic linker
|
||||||
var maybe_interp_base: ?usize = null;
|
var maybe_interp_base: ?usize = null;
|
||||||
@@ -102,6 +103,7 @@ pub fn main() !void {
|
|||||||
"Interpreter loaded: base=0x{x}, entry=0x{x}",
|
"Interpreter loaded: base=0x{x}, entry=0x{x}",
|
||||||
.{ interp_base, maybe_interp_entry.? },
|
.{ interp_base, maybe_interp_entry.? },
|
||||||
);
|
);
|
||||||
|
try patchLoadedElf(interp_base);
|
||||||
interp.close();
|
interp.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,16 +212,44 @@ fn loadStaticElf(ehdr: elf.Header, file_reader: *std.fs.File.Reader) !usize {
|
|||||||
return UnfinishedReadError.UnfinishedRead;
|
return UnfinishedReadError.UnfinishedRead;
|
||||||
|
|
||||||
const protections = elfToMmapProt(phdr.p_flags);
|
const protections = elfToMmapProt(phdr.p_flags);
|
||||||
if (protections & posix.PROT.EXEC > 0) {
|
|
||||||
log.info("Patching executable segment", .{});
|
|
||||||
try Patcher.patchRegion(ptr);
|
|
||||||
}
|
|
||||||
try posix.mprotect(ptr, protections);
|
try posix.mprotect(ptr, protections);
|
||||||
}
|
}
|
||||||
log.debug("loadElf returning base: 0x{x}", .{@intFromPtr(base.ptr)});
|
log.debug("loadElf returning base: 0x{x}", .{@intFromPtr(base.ptr)});
|
||||||
return @intFromPtr(base.ptr);
|
return @intFromPtr(base.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn patchLoadedElf(base: usize) !void {
|
||||||
|
const ehdr = @as(*const elf.Ehdr, @ptrFromInt(base));
|
||||||
|
if (!mem.eql(u8, ehdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
|
||||||
|
|
||||||
|
const phoff = ehdr.e_phoff;
|
||||||
|
const phnum = ehdr.e_phnum;
|
||||||
|
const phentsize = ehdr.e_phentsize;
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < phnum) : (i += 1) {
|
||||||
|
const phdr_ptr = base + phoff + (i * phentsize);
|
||||||
|
const phdr = @as(*const elf.Phdr, @ptrFromInt(phdr_ptr));
|
||||||
|
|
||||||
|
if (phdr.p_type != elf.PT_LOAD) continue;
|
||||||
|
if ((phdr.p_flags & elf.PF_X) == 0) continue;
|
||||||
|
|
||||||
|
// Determine VMA
|
||||||
|
// For ET_EXEC, p_vaddr is absolute.
|
||||||
|
// For ET_DYN, p_vaddr is offset from base.
|
||||||
|
const vaddr = if (ehdr.e_type == elf.ET.DYN) base + phdr.p_vaddr else phdr.p_vaddr;
|
||||||
|
const memsz = phdr.p_memsz;
|
||||||
|
|
||||||
|
const page_start = mem.alignBackward(usize, vaddr, page_size);
|
||||||
|
const page_end = mem.alignForward(usize, vaddr + memsz, page_size);
|
||||||
|
|
||||||
|
const region = @as([*]align(page_size) u8, @ptrFromInt(page_start))[0 .. page_end - page_start];
|
||||||
|
|
||||||
|
log.info("Patching segment: 0x{x} - 0x{x}", .{ page_start, page_end });
|
||||||
|
try Patcher.patchRegion(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts ELF program header protection flags to mmap protection flags.
|
/// Converts ELF program header protection flags to mmap protection flags.
|
||||||
fn elfToMmapProt(elf_prot: u64) u32 {
|
fn elfToMmapProt(elf_prot: u64) u32 {
|
||||||
var result: u32 = posix.PROT.NONE;
|
var result: u32 = posix.PROT.NONE;
|
||||||
|
|||||||
Reference in New Issue
Block a user