fix msim to load non page aligned segments
This commit is contained in:
parent
9ae3442c85
commit
5befb8b4e6
2 changed files with 88 additions and 69 deletions
138
msim/load.c
138
msim/load.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue