elf: Add elf*_load_elsewhere() functions

This commit is contained in:
mintsuki 2022-06-29 08:16:22 +02:00
parent 4e0ec6d544
commit e436b763c2
3 changed files with 162 additions and 1 deletions

View File

@ -87,4 +87,10 @@ noreturn void common_spinup(void *fnptr, int args, ...);
#define no_unwind __attribute__((section(".no_unwind")))
struct elsewhere_range {
uint64_t elsewhere;
uint64_t target;
uint64_t length;
};
#endif

View File

@ -764,3 +764,151 @@ int elf32_load(uint8_t *elf, uint32_t *entry_point, uint32_t *top, uint32_t allo
return 0;
}
bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges,
size_t *ranges_count) {
struct elf32_hdr *hdr = (void *)elf;
if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
printv("elf: Not a valid ELF file.\n");
return false;
}
if (hdr->ident[EI_DATA] != BITS_LE) {
printv("elf: Not a Little-endian ELF file.\n");
return false;
}
if (hdr->machine != ARCH_X86_32) {
printv("elf: Not an x86_32 ELF file.\n");
return false;
}
*entry_point = hdr.entry;
bool entry_adjusted = false;
if (hdr->phdr_size < sizeof(struct elf32_phdr)) {
panic(true, "elf: phdr_size < sizeof(struct elf32_phdr)");
}
*ranges_count = 0;
for (uint16_t i = 0; i < hdr->ph_num; i++) {
struct elf32_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
if (phdr->p_type != PT_LOAD)
continue;
*ranges_count += 1;
}
*ranges = ext_mem_alloc(sizeof(struct elsewhere_range) * *ranges_count);
size_t cur_entry = 0;
for (uint16_t i = 0; i < hdr->ph_num; i++) {
struct elf32_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
if (phdr->p_type != PT_LOAD)
continue;
// Sanity checks
if (phdr->p_filesz > phdr.p_memsz) {
panic(true, "elf: p_filesz > p_memsz");
}
void *elsewhere = ext_mem_alloc(phdr.p_memsz);
memcpy(elsewhere, elf + phdr.p_offset, phdr.p_filesz);
if (!entry_adjusted
&& *entry_point >= phdr.p_vaddr
&& *entry_point < (phdr.p_vaddr + phdr.p_memsz)) {
*entry_point -= phdr.p_vaddr;
*entry_point += phdr.p_paddr;
entry_adjusted = true;
}
*entry[cur_entry].elsewhere = elsewhere;
*entry[cur_entry].target = phdr.p_paddr;
*entry[cur_entry].length = phdr.p_memsz;
cur_entry++;
}
return true;
}
bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges,
size_t *ranges_count) {
struct elf64_hdr *hdr = (void *)elf;
if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
printv("elf: Not a valid ELF file.\n");
return false;
}
if (hdr->ident[EI_DATA] != BITS_LE) {
printv("elf: Not a Little-endian ELF file.\n");
return false;
}
if (hdr->machine != ARCH_X86_64) {
printv("elf: Not an x86_64 ELF file.\n");
return false;
}
*entry_point = hdr.entry;
bool entry_adjusted = false;
if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
panic(true, "elf: phdr_size < sizeof(struct elf64_phdr)");
}
*ranges_count = 0;
for (uint16_t i = 0; i < hdr->ph_num; i++) {
struct elf64_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
if (phdr->p_type != PT_LOAD)
continue;
*ranges_count += 1;
}
*ranges = ext_mem_alloc(sizeof(struct elsewhere_range) * *ranges_count);
size_t cur_entry = 0;
for (uint16_t i = 0; i < hdr->ph_num; i++) {
struct elf64_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
if (phdr->p_type != PT_LOAD)
continue;
// Sanity checks
if (phdr->p_filesz > phdr.p_memsz) {
panic(true, "elf: p_filesz > p_memsz");
}
void *elsewhere = ext_mem_alloc(phdr.p_memsz);
memcpy(elsewhere, elf + phdr.p_offset, phdr.p_filesz);
if (!entry_adjusted
&& *entry_point >= phdr.p_vaddr
&& *entry_point < (phdr.p_vaddr + phdr.p_memsz)) {
*entry_point -= phdr.p_vaddr;
*entry_point += phdr.p_paddr;
entry_adjusted = true;
}
*entry[cur_entry].elsewhere = elsewhere;
*entry[cur_entry].target = phdr.p_paddr;
*entry[cur_entry].length = phdr.p_memsz;
cur_entry++;
}
return true;
}

View File

@ -3,7 +3,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <fs/file.h>
#include <lib/blib.h>
#define FIXED_HIGHER_HALF_OFFSET_64 ((uint64_t)0xffffffff80000000)
@ -34,6 +34,13 @@ int elf32_load(uint8_t *elf, uint32_t *entry_point, uint32_t *top, uint32_t allo
int elf32_load_section(uint8_t *elf, void *buffer, const char *name, size_t limit);
struct elf_section_hdr_info* elf32_section_hdr_info(uint8_t *elf);
bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges,
size_t *ranges_count);
bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges,
size_t *ranges_count);
struct elf64_hdr {
uint8_t ident[16];
uint16_t type;