mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 06:58:22 +00:00
elf: fix zeroing of first loaded page, header base and stack alignment
This commit is contained in:
+37
-14
@@ -29,9 +29,9 @@ static bool headerok(elfheader64_t *header) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int readexact(vnode_t *vnode, void *pos, size_t count, uintmax_t offset) {
|
static int readexact(vnode_t *vnode, void *buff, size_t count, uintmax_t offset) {
|
||||||
size_t readc;
|
size_t readc;
|
||||||
int e = vfs_read(vnode, pos, count, offset, &readc, 0);
|
int e = vfs_read(vnode, buff, count, offset, &readc, 0);
|
||||||
if (e)
|
if (e)
|
||||||
return e;
|
return e;
|
||||||
if (readc != count)
|
if (readc != count)
|
||||||
@@ -53,7 +53,6 @@ static mmuflags_t flagstommuflags(int flags) {
|
|||||||
|
|
||||||
static int load(vnode_t *vnode, elfph64_t *ph) {
|
static int load(vnode_t *vnode, elfph64_t *ph) {
|
||||||
// TODO verify that the load address doesn't intersect the kernel
|
// TODO verify that the load address doesn't intersect the kernel
|
||||||
printf("loading ph at %p with mem size %lu, disk size %lu and flags %x\n", ph->memaddr, ph->msize, ph->fsize, ph->flags);
|
|
||||||
int error = 0;
|
int error = 0;
|
||||||
uintmax_t foffset = ph->offset;
|
uintmax_t foffset = ph->offset;
|
||||||
uintptr_t mempos = ph->memaddr;
|
uintptr_t mempos = ph->memaddr;
|
||||||
@@ -81,6 +80,14 @@ static int load(vnode_t *vnode, elfph64_t *ph) {
|
|||||||
msize -= firstpagecount;
|
msize -= firstpagecount;
|
||||||
fsize -= firstpagecount;
|
fsize -= firstpagecount;
|
||||||
foffset += firstpagecount;
|
foffset += firstpagecount;
|
||||||
|
uintmax_t remaining = mempos % PAGE_SIZE;
|
||||||
|
// zero remaining parts of the first page if needed
|
||||||
|
if (remaining && msize) {
|
||||||
|
size_t remainingmsize = remaining > msize ? msize : remaining;
|
||||||
|
memset((void *)mempos, 0, remainingmsize);
|
||||||
|
msize -= remainingmsize;
|
||||||
|
mempos += remainingmsize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// map middle of file
|
// map middle of file
|
||||||
@@ -149,7 +156,7 @@ int elf_load(vnode_t *vnode, void *base, void **entry, char **interpreter, auxv6
|
|||||||
auxv64->phnum.val = header.phcount;
|
auxv64->phnum.val = header.phcount;
|
||||||
auxv64->phent.val = header.phsize;
|
auxv64->phent.val = header.phsize;
|
||||||
auxv64->entry.val = header.entry;
|
auxv64->entry.val = header.entry;
|
||||||
*entry = (void *)header.entry;
|
*entry = (void *)(header.entry + (uintptr_t)base);
|
||||||
|
|
||||||
__assert(header.phsize == sizeof(elfph64_t));
|
__assert(header.phsize == sizeof(elfph64_t));
|
||||||
|
|
||||||
@@ -165,6 +172,7 @@ int elf_load(vnode_t *vnode, void *base, void **entry, char **interpreter, auxv6
|
|||||||
elfph64_t *interpreterph = NULL;
|
elfph64_t *interpreterph = NULL;
|
||||||
|
|
||||||
for (int i = 0; i < header.phcount; ++i) {
|
for (int i = 0; i < header.phcount; ++i) {
|
||||||
|
headers[i].memaddr += (uintptr_t)base;
|
||||||
switch (headers[i].type) {
|
switch (headers[i].type) {
|
||||||
case PH_TYPE_INTERPRETER:
|
case PH_TYPE_INTERPRETER:
|
||||||
interpreterph = &headers[i];
|
interpreterph = &headers[i];
|
||||||
@@ -173,7 +181,6 @@ int elf_load(vnode_t *vnode, void *base, void **entry, char **interpreter, auxv6
|
|||||||
auxv64->phdr.val = headers[i].memaddr;
|
auxv64->phdr.val = headers[i].memaddr;
|
||||||
break;
|
break;
|
||||||
case PH_TYPE_LOAD:
|
case PH_TYPE_LOAD:
|
||||||
headers[i].memaddr += (uintptr_t)base;
|
|
||||||
err = load(vnode, &headers[i]);
|
err = load(vnode, &headers[i]);
|
||||||
if (err)
|
if (err)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -182,8 +189,15 @@ int elf_load(vnode_t *vnode, void *base, void **entry, char **interpreter, auxv6
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (interpreterph) {
|
if (interpreterph) {
|
||||||
printf("dp: %lu dl: %lu mp: %p ml: %lu\n", interpreterph->offset, interpreterph->fsize, interpreterph->memaddr, interpreterph->msize);
|
char *buff = alloc(interpreterph->fsize);
|
||||||
__assert(!"UNIMPLEMENTED");
|
if (buff == NULL) {
|
||||||
|
err = ENOMEM;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
err = readexact(vnode, buff, interpreterph->fsize, interpreterph->offset);
|
||||||
|
if (err)
|
||||||
|
goto cleanup;
|
||||||
|
*interpreter = buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@@ -192,6 +206,7 @@ int elf_load(vnode_t *vnode, void *base, void **entry, char **interpreter, auxv6
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define STACK_MMUFLAGS (ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC | ARCH_MMU_FLAGS_USER)
|
#define STACK_MMUFLAGS (ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC | ARCH_MMU_FLAGS_USER)
|
||||||
|
#define STACK_SIZE (1024 * 1024 * 4)
|
||||||
|
|
||||||
void *elf_preparestack(void *top, auxv64list_t *auxv64, char **argv, char **envp) {
|
void *elf_preparestack(void *top, auxv64list_t *auxv64, char **argv, char **envp) {
|
||||||
size_t argc;
|
size_t argc;
|
||||||
@@ -205,23 +220,31 @@ void *elf_preparestack(void *top, auxv64list_t *auxv64, char **argv, char **envp
|
|||||||
for (envc = 0; envp[envc]; ++envc)
|
for (envc = 0; envp[envc]; ++envc)
|
||||||
envdatasize += strlen(envp[envc]) + 1;
|
envdatasize += strlen(envp[envc]) + 1;
|
||||||
|
|
||||||
|
// make sure stack will be 16 byte aligned on entry
|
||||||
|
int alignment = ((argc + 1) + (envc + 1) + 1) & 1 ? 8 : 0;
|
||||||
|
|
||||||
// env data + arg data + pointers to arg and env data + argc
|
// env data + arg data + pointers to arg and env data + argc
|
||||||
size_t initialsize = argdatasize + envdatasize + (argc + envc) * sizeof(char *) + sizeof(size_t) + sizeof(auxv64list_t);
|
size_t initialsize = argdatasize + envdatasize + (argc + envc) * sizeof(char *) + sizeof(size_t) + sizeof(auxv64list_t) + alignment;
|
||||||
|
|
||||||
size_t initialsizeround = ROUND_UP(initialsize, PAGE_SIZE);
|
size_t initialsizeround = ROUND_UP(initialsize, PAGE_SIZE);
|
||||||
void *initialpagebase = (void *)((uintptr_t)top - initialsizeround);
|
void *initialpagebase = (void *)((uintptr_t)top - initialsizeround);
|
||||||
|
|
||||||
if (vmm_map(initialpagebase, initialsizeround, VMM_FLAGS_ALLOCATE | VMM_FLAGS_EXACT, STACK_MMUFLAGS, NULL) == NULL)
|
if (vmm_map(initialpagebase, initialsizeround, VMM_FLAGS_ALLOCATE | VMM_FLAGS_EXACT, STACK_MMUFLAGS, NULL) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
auxv64list_t *auxvstart = (auxv64list_t *)top - 1;
|
void *stackbase = (void *)((uintptr_t)top - STACK_SIZE);
|
||||||
char *argdatastart = (char *)((uintptr_t)auxvstart - argdatasize);
|
size_t unallocatedsize = STACK_SIZE - initialsizeround;
|
||||||
|
if (vmm_map(stackbase, unallocatedsize, VMM_FLAGS_EXACT, STACK_MMUFLAGS, NULL) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
char *argdatastart = (char *)((uintptr_t)top - argdatasize);
|
||||||
char *envdatastart = (char *)((uintptr_t)argdatastart - envdatasize);
|
char *envdatastart = (char *)((uintptr_t)argdatastart - envdatasize);
|
||||||
|
auxv64list_t *auxvstart = (auxv64list_t *)envdatastart - 1;
|
||||||
|
|
||||||
|
auxvstart = (auxv64list_t *)(((uintptr_t)auxvstart & ~(uintptr_t)0xf) - alignment);
|
||||||
|
|
||||||
// also leave space for null entry
|
// also leave space for null entry
|
||||||
char **envstart = (char **)envdatastart - envc - 1;
|
char **envstart = (char **)auxvstart - envc - 1;
|
||||||
// round down to 16 bytes
|
|
||||||
envstart = (char **)((uintptr_t)envstart & ~(uintptr_t)0xf);
|
|
||||||
char **argstart = (char **)envstart - argc - 1;
|
char **argstart = (char **)envstart - argc - 1;
|
||||||
size_t *argcptr = (size_t *)argstart - 1;
|
size_t *argcptr = (size_t *)argstart - 1;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user