fix msim to load non page aligned segments

This commit is contained in:
Freya Murphy 2024-10-04 22:09:42 -04:00
parent 9ae3442c85
commit 5befb8b4e6
Signed by: freya
GPG key ID: 744AB800E383AE52
2 changed files with 88 additions and 69 deletions

View file

@ -9,6 +9,9 @@
#include "sim.h" #include "sim.h"
#define SEC_ALIGN 0x1000 #define SEC_ALIGN 0x1000
#define PAGE_SIZE 4096
#define BITFILED_LEN (UINT32_MAX / PAGE_SIZE / 8)
struct load_state { struct load_state {
FILE *file; FILE *file;
@ -106,94 +109,111 @@ static int load_phdr(struct load_state *state)
return M_SUCCESS; return M_SUCCESS;
} }
static int load_segment(struct simulator *sim, static void set_page(uint8_t *bitfield, uint32_t addr)
struct load_state *state, Elf32_Phdr *hdr)
{ {
uint32_t off = B32(hdr->p_offset); int idx = (addr / PAGE_SIZE) / 8;
uint32_t len = B32(hdr->p_filesz); int off = (addr / PAGE_SIZE) % 8;
uint32_t is_text = B32(hdr->p_flags) & PF_X;
bitfield[idx] |= 1 << off;
}
static int get_page(const uint8_t *const bitfield, uint32_t addr)
{
int idx = (addr / PAGE_SIZE) / 8;
int off = (addr / PAGE_SIZE) % 8;
return ((bitfield[idx] >> off) & 1);
}
static int load_segment(struct simulator *sim, struct load_state *state,
Elf32_Phdr *hdr, uint8_t* bitfield)
{
uint32_t addr = B32(hdr->p_vaddr),
off = B32(hdr->p_offset),
len = B32(hdr->p_filesz),
flags = B32(hdr->p_flags);
bool exec = flags & PF_X;
// ignore if empty
if (len < 1)
return M_SUCCESS;
// make sure segment is acutally inside
// the file
if (BOUND_CHK(state->file_sz, len, off)) { if (BOUND_CHK(state->file_sz, len, off)) {
ERROR("segment location invalid"); ERROR("segment location invalid");
return M_ERROR; return M_ERROR;
} }
uintptr_t addr = 0; // make sure the vitural address is also
uint32_t add = 0; // valid
if (BOUND_CHK(UINT32_MAX, len, addr)) {
if (len % SEC_ALIGN) { ERROR("segment vitural addr invalid");
add = SEC_ALIGN - (len % SEC_ALIGN); return M_ERROR;
len += add;
} }
if (is_text) { // update text seg bounds
addr = sim->text_max; if (exec) {
sim->text_max += len; if (addr < sim->text_min)
} else { sim->text_min = addr;
addr = sim->data_max; if (addr + len > sim->text_max)
sim->data_max += len; sim->text_max = addr + len;
} }
bool read = B32(hdr->p_flags) & PF_R; // align the mapping ptr to
bool write = B32(hdr->p_flags) & PF_W; // the page size
uintptr_t ptr = (addr / PAGE_SIZE) * PAGE_SIZE;
uint32_t prot = 0; // map each page that the segment
if (read) // requires
prot |= PROT_READ; for (; ptr < addr + len; ptr += PAGE_SIZE) {
if (write) // dont remap if address is
prot |= PROT_WRITE; // already mapped
if (get_page(bitfield, ptr))
continue;
void *res = mmap((void*)addr, len, prot, MAP_PRIVATE | MAP_FIXED, // set page as mapped
state->fd, off); set_page(bitfield, ptr);
if ((uintptr_t)res != addr) { void *res = mmap(
(void *) ptr, PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if ((uintptr_t) res != ptr) {
PERROR("failed to map executable"); PERROR("failed to map executable");
return M_ERROR; return M_ERROR;
} }
}
// load the segment into the mapped memory
fseek(state->file, off, SEEK_SET);
fread((void *) (uintptr_t) addr, 1, len, state->file);
return M_SUCCESS; return M_SUCCESS;
} }
static int load_memory(struct simulator *sim, struct load_state *state) static int load_memory(struct simulator *sim, struct load_state *state)
{ {
uint32_t base = 0; // map each page in a 32bit address space to a single bit
// in the bitfield
uint8_t *bitfield = malloc(BITFILED_LEN);
if (bitfield == NULL) {
PERROR("cannot alloc");
return M_ERROR;
}
memset(bitfield, 0, BITFILED_LEN);
for (uint32_t i = 0; i < state->phdr_len; i++) { for (uint32_t i = 0; i < state->phdr_len; i++) {
Elf32_Phdr *hdr = NULL; Elf32_Phdr *hdr = &state->phdr[i];
uint32_t min = UINT32_MAX;
if (B32(state->phdr[i].p_filesz) < 1) if (load_segment(sim, state, hdr, bitfield))
continue;
// we need to load segments in order
for (uint32_t j = 0; j < state->phdr_len; j++) {
Elf32_Phdr *temp = &state->phdr[j];
uint32_t off = B32(temp->p_offset);
uint32_t len = B32(temp->p_filesz);
if (len < 1)
continue;
if (off <= base)
continue;
if (off >= min)
continue;
min = off;
hdr = temp;
}
base = min;
if (hdr == NULL) {
ERROR("invalid elf phdr");
return M_ERROR; return M_ERROR;
} }
if (load_segment(sim, state, hdr)) free(bitfield);
return M_ERROR;
}
return M_SUCCESS; return M_SUCCESS;
} }

View file

@ -34,7 +34,6 @@ struct simulator_args {
struct simulator { struct simulator {
struct simulator_args *args; struct simulator_args *args;
/// the registers /// the registers
uint32_t reg[32]; uint32_t reg[32];