diff options
Diffstat (limited to 'exec.c')
-rw-r--r-- | exec.c | 136 |
1 files changed, 136 insertions, 0 deletions
@@ -0,0 +1,136 @@ +#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; + struct inode *ip; + struct elfhdr elf; + struct proghdr ph; + char *mem; + char *s, *last; + + sz = 0; + mem = 0; + + if((ip = namei(path)) == 0) + return -1; + + if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) + goto bad; + + if(elf.magic != ELF_MAGIC) + goto bad; + + for(i = 0; i < elf.phnum; i++){ + if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph), + sizeof(ph)) != sizeof(ph)) + goto bad; + if(ph.type != ELF_PROG_LOAD) + continue; + if(ph.memsz < ph.filesz) + goto bad; + sz += ph.memsz; + } + + sz += 4096 - (sz % 4096); + sz += 4096; + + 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; + } + 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; + } + *(uint*)(mem + p1) = 0; + + // Save 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->sz = sz; + cp->mem = mem; + mem = 0; + + for(i = 0; i < elf.phnum; i++){ + if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph), + 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); + } + + iput(ip); + + cp->tf->eip = elf.entry; + cp->tf->esp = sp; + setupsegs(cp); + + return 0; + + bad: + if(mem) + kfree(mem, sz); + iput(ip); + return -1; + + bad2: + iput(ip); + proc_exit(); + return 0; +} |