diff options
Diffstat (limited to 'exec.c')
-rw-r--r-- | exec.c | 136 |
1 files changed, 59 insertions, 77 deletions
@@ -1,44 +1,35 @@ #include "types.h" -#include "stat.h" #include "param.h" #include "mmu.h" #include "proc.h" #include "defs.h" #include "x86.h" -#include "traps.h" -#include "syscall.h" -#include "spinlock.h" -#include "buf.h" #include "fs.h" -#include "fsvar.h" #include "elf.h" -#include "file.h" -#include "fcntl.h" int exec(char *path, char **argv) { - uint sz, sp, p1, p2; - int i, nargs, argbytes, len, off; - struct inode *ip; + char *mem, *s, *last; + int i, argc, arglen, len, off; + uint sz, sp, argp; struct elfhdr elf; + struct inode *ip; struct proghdr ph; - char *mem; - char *s, *last; - - sz = 0; - mem = 0; 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; @@ -48,77 +39,73 @@ exec(char *path, char **argv) goto bad; sz += ph.memsz; } - - sz += 4096 - (sz % 4096); - sz += 4096; - + + // 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); - argbytes = 0; - for(i = 0; argv[i]; i++){ - len = strlen(argv[i]); - argbytes += len + 1; + // 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); } - nargs = i; - - // argn\0 - // ... - // arg0\0 - // 0 - // ptr to argn - // ... - // 12: ptr to arg0 - // 8: argv (points to ptr to arg0) - // 4: argc - // 0: fake return pc - sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4; - *(uint*)(mem + sp) = 0xffffffff; - *(uint*)(mem + sp + 4) = nargs; - *(uint*)(mem + sp + 8) = (uint)(sp + 12); - - p1 = sp + 12; - p2 = sp + 12 + (nargs + 1) * 4; - for(i = 0; i < nargs; i++){ - len = strlen(argv[i]); - memmove(mem + p2, argv[i], len + 1); - *(uint*)(mem + p1) = p2; - p1 += 4; - p2 += len + 1; + 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] } - *(uint*)(mem + p1) = 0; - // Save name for debugging. + // 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. + // Commit to the new image. kfree(cp->mem, cp->sz); - cp->sz = sz; cp->mem = mem; - mem = 0; - - for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ - if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) - goto bad2; - if(ph.type != ELF_PROG_LOAD) - continue; - if(ph.va + ph.memsz > sz) - goto bad2; - if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz) - goto bad2; - memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz); - } - iunlockput(ip); - - cp->tf->eip = elf.entry; + cp->sz = sz; + cp->tf->eip = elf.entry; // main cp->tf->esp = sp; setupsegs(cp); - return 0; bad: @@ -126,9 +113,4 @@ exec(char *path, char **argv) kfree(mem, sz); iunlockput(ip); return -1; - - bad2: - iunlockput(ip); - proc_exit(); - return 0; } |