| 1 |
/* elf.c - ELF64 loader for Pactor64 */ |
| 2 |
#include "elf.h" |
| 3 |
|
| 4 |
int elf64_validate(const void *file_data, uint32_t file_size) { |
| 5 |
if (file_size < sizeof(elf64_ehdr_t)) { |
| 6 |
kprintf("[elf] File too small for ELF header\n"); |
| 7 |
return -1; |
| 8 |
} |
| 9 |
|
| 10 |
const elf64_ehdr_t *ehdr = (const elf64_ehdr_t *)file_data; |
| 11 |
|
| 12 |
if (ehdr->e_ident[0] != ELFMAG0 || ehdr->e_ident[1] != ELFMAG1 || |
| 13 |
ehdr->e_ident[2] != ELFMAG2 || ehdr->e_ident[3] != ELFMAG3) { |
| 14 |
kprintf("[elf] Bad ELF magic\n"); |
| 15 |
return -1; |
| 16 |
} |
| 17 |
if (ehdr->e_ident[4] != ELFCLASS64) { |
| 18 |
kprintf("[elf] Not a 64-bit ELF (class=%d)\n", ehdr->e_ident[4]); |
| 19 |
return -1; |
| 20 |
} |
| 21 |
if (ehdr->e_ident[5] != ELFDATA2LSB) { |
| 22 |
kprintf("[elf] Not little-endian\n"); |
| 23 |
return -1; |
| 24 |
} |
| 25 |
if (ehdr->e_type != ET_EXEC) { |
| 26 |
kprintf("[elf] Not an executable (type=%d)\n", ehdr->e_type); |
| 27 |
return -1; |
| 28 |
} |
| 29 |
if (ehdr->e_machine != EM_X86_64) { |
| 30 |
kprintf("[elf] Not x86-64 (machine=%d)\n", ehdr->e_machine); |
| 31 |
return -1; |
| 32 |
} |
| 33 |
if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > file_size) { |
| 34 |
kprintf("[elf] Program header table extends beyond file\n"); |
| 35 |
return -1; |
| 36 |
} |
| 37 |
return 0; |
| 38 |
} |
| 39 |
|
| 40 |
elf64_load_result_t elf64_load(const void *file_data, uint32_t file_size) { |
| 41 |
elf64_load_result_t result; |
| 42 |
result.valid = 0; |
| 43 |
result.entry = 0; |
| 44 |
result.load_base = 0xFFFFFFFFFFFFFFFFULL; |
| 45 |
result.load_end = 0; |
| 46 |
|
| 47 |
if (elf64_validate(file_data, file_size) != 0) return result; |
| 48 |
|
| 49 |
const elf64_ehdr_t *ehdr = (const elf64_ehdr_t *)file_data; |
| 50 |
result.entry = ehdr->e_entry; |
| 51 |
|
| 52 |
kprintf("[elf] Entry point: 0x%x\n", result.entry); |
| 53 |
kprintf("[elf] Program headers: %d\n", ehdr->e_phnum); |
| 54 |
|
| 55 |
const uint8_t *base = (const uint8_t *)file_data; |
| 56 |
for (uint16_t i = 0; i < ehdr->e_phnum; i++) { |
| 57 |
const elf64_phdr_t *phdr = (const elf64_phdr_t *) |
| 58 |
(base + ehdr->e_phoff + i * ehdr->e_phentsize); |
| 59 |
|
| 60 |
if (phdr->p_type != PT_LOAD) continue; |
| 61 |
|
| 62 |
kprintf("[elf] PT_LOAD[%d]: vaddr=0x%x filesz=0x%x memsz=0x%x flags=%c%c%c\n", |
| 63 |
i, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz, |
| 64 |
(phdr->p_flags & PF_R) ? 'R' : '-', |
| 65 |
(phdr->p_flags & PF_W) ? 'W' : '-', |
| 66 |
(phdr->p_flags & PF_X) ? 'E' : '-'); |
| 67 |
|
| 68 |
if (phdr->p_offset + phdr->p_filesz > file_size) { |
| 69 |
kprintf("[elf] Segment extends beyond file\n"); |
| 70 |
return result; |
| 71 |
} |
| 72 |
|
| 73 |
void *dest = (void *)(uintptr_t)phdr->p_vaddr; |
| 74 |
kmemset(dest, 0, phdr->p_memsz); |
| 75 |
if (phdr->p_filesz > 0) { |
| 76 |
kmemcpy(dest, base + phdr->p_offset, phdr->p_filesz); |
| 77 |
} |
| 78 |
|
| 79 |
if (phdr->p_vaddr < result.load_base) |
| 80 |
result.load_base = phdr->p_vaddr; |
| 81 |
if (phdr->p_vaddr + phdr->p_memsz > result.load_end) |
| 82 |
result.load_end = phdr->p_vaddr + phdr->p_memsz; |
| 83 |
} |
| 84 |
|
| 85 |
result.valid = 1; |
| 86 |
kprintf("[elf] Loaded at 0x%x - 0x%x, entry at 0x%x\n", |
| 87 |
result.load_base, result.load_end, result.entry); |
| 88 |
return result; |
| 89 |
} |
| 90 |
|
| 91 |
uint64_t elf64_get_entry(const void *file_data) { |
| 92 |
const elf64_ehdr_t *ehdr = (const elf64_ehdr_t *)file_data; |
| 93 |
return ehdr->e_entry; |
| 94 |
} |
| 95 |
|