629c1fe743
Do not commit to new memory image until nothing can go wrong, avoiding bad2 case. Be sure to allocate enough stack space for argv. Load executable before initializing stack, to keep ELF loops together. Make argv loop clearer.
116 lines
2.5 KiB
C
116 lines
2.5 KiB
C
#include "types.h"
|
|
#include "param.h"
|
|
#include "mmu.h"
|
|
#include "proc.h"
|
|
#include "defs.h"
|
|
#include "x86.h"
|
|
#include "fs.h"
|
|
#include "elf.h"
|
|
|
|
int
|
|
exec(char *path, char **argv)
|
|
{
|
|
char *mem, *s, *last;
|
|
int i, argc, arglen, len, off;
|
|
uint sz, sp, argp;
|
|
struct elfhdr elf;
|
|
struct inode *ip;
|
|
struct proghdr ph;
|
|
|
|
if((ip = namei(path)) == 0)
|
|
return -1;
|
|
ilock(ip);
|
|
|
|
// Compute memory size of new process.
|
|
mem = 0;
|
|
sz = 0;
|
|
|
|
// Program segments.
|
|
if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
|
|
goto bad;
|
|
if(elf.magic != ELF_MAGIC)
|
|
goto bad;
|
|
for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
|
|
if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))
|
|
goto bad;
|
|
if(ph.type != ELF_PROG_LOAD)
|
|
continue;
|
|
if(ph.memsz < ph.filesz)
|
|
goto bad;
|
|
sz += ph.memsz;
|
|
}
|
|
|
|
// Arguments.
|
|
arglen = 0;
|
|
for(argc=0; argv[argc]; argc++)
|
|
arglen += strlen(argv[i]) + 1;
|
|
arglen = (arglen+3) & ~3;
|
|
sz += arglen + 4*(argc+1);
|
|
|
|
// Stack.
|
|
sz += PAGE;
|
|
|
|
// Allocate program memory.
|
|
sz = (sz+PAGE-1) & ~(PAGE-1);
|
|
mem = kalloc(sz);
|
|
if(mem == 0)
|
|
goto bad;
|
|
memset(mem, 0, sz);
|
|
|
|
// Load program into memory.
|
|
for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
|
|
if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))
|
|
goto bad;
|
|
if(ph.type != ELF_PROG_LOAD)
|
|
continue;
|
|
if(ph.va + ph.memsz > sz)
|
|
goto bad;
|
|
if(readi(ip, mem + ph.va, ph.offset, ph.filesz) != ph.filesz)
|
|
goto bad;
|
|
memset(mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
|
|
}
|
|
iunlockput(ip);
|
|
|
|
// Initialize stack.
|
|
sp = sz;
|
|
argp = sz - arglen;
|
|
|
|
// Copy argv strings and pointers to stack.
|
|
*(uint*)(mem+argp + 4*argc) = 0; // argv[argc]
|
|
for(i=argc-1; i>=0; i--){
|
|
len = strlen(argv[i]) + 1;
|
|
sp -= len;
|
|
memmove(mem+sp, argv[i], len);
|
|
*(uint*)(mem+argp + 4*i) = sp; // argv[i]
|
|
}
|
|
|
|
// Stack frame for main(argc, argv), below arguments.
|
|
sp = argp;
|
|
sp -= 4;
|
|
*(uint*)(mem+sp) = argp;
|
|
sp -= 4;
|
|
*(uint*)(mem+sp) = argc;
|
|
sp -= 4;
|
|
*(uint*)(mem+sp) = 0xffffffff; // fake return pc
|
|
|
|
// Save program name for debugging.
|
|
for(last=s=path; *s; s++)
|
|
if(*s == '/')
|
|
last = s+1;
|
|
safestrcpy(cp->name, last, sizeof(cp->name));
|
|
|
|
// Commit to the new image.
|
|
kfree(cp->mem, cp->sz);
|
|
cp->mem = mem;
|
|
cp->sz = sz;
|
|
cp->tf->eip = elf.entry; // main
|
|
cp->tf->esp = sp;
|
|
setupsegs(cp);
|
|
return 0;
|
|
|
|
bad:
|
|
if(mem)
|
|
kfree(mem, sz);
|
|
iunlockput(ip);
|
|
return -1;
|
|
}
|