elf: Add elf*_load_elsewhere() functions
This commit is contained in:
parent
4e0ec6d544
commit
e436b763c2
|
@ -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
|
||||
|
|
148
common/lib/elf.c
148
common/lib/elf.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue