#include "types.h" #include "param.h" #include "mmu.h" #include "proc.h" #include "defs.h" #include "x86.h" #include "elf.h" int exec(char *path, char **argv) { char *mem, *s, *last; int i, argc, arglen, len, off; uint sz, sp, spbottom, argp; struct elfhdr elf; struct inode *ip; struct proghdr ph; pde_t *pgdir, *oldpgdir; pgdir = 0; sz = 0; if((ip = namei(path)) == 0) return -1; ilock(ip); // Check ELF header if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) goto bad; if(elf.magic != ELF_MAGIC) goto bad; if(!(pgdir = setupkvm())) goto bad; // 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.memsz < ph.filesz) goto bad; if(!(sz = allocuvm(pgdir, sz, ph.va + ph.memsz))) goto bad; if(!loaduvm(pgdir, (char *)ph.va, ip, ph.offset, ph.filesz)) goto bad; } iunlockput(ip); // Allocate and initialize stack at sz sz = spbottom = PGROUNDUP(sz); if(!(sz = allocuvm(pgdir, sz, sz + PGSIZE))) goto bad; mem = uva2ka(pgdir, (char *)spbottom); arglen = 0; for(argc=0; argv[argc]; argc++) arglen += strlen(argv[argc]) + 1; arglen = (arglen+3) & ~3; sp = sz; argp = sz - arglen - 4*(argc+1); // XXX rtm: does the following code work if the // arguments &c do not fit in one page? // Copy argv strings and pointers to stack. *(uint*)(mem+argp-spbottom + 4*argc) = 0; // argv[argc] for(i=argc-1; i>=0; i--){ len = strlen(argv[i]) + 1; sp -= len; memmove(mem+sp-spbottom, argv[i], len); *(uint*)(mem+argp-spbottom + 4*i) = sp; // argv[i] } // Stack frame for main(argc, argv), below arguments. sp = argp; sp -= 4; *(uint*)(mem+sp-spbottom) = argp; sp -= 4; *(uint*)(mem+sp-spbottom) = argc; sp -= 4; *(uint*)(mem+sp-spbottom) = 0xffffffff; // fake return pc // Save program name for debugging. for(last=s=path; *s; s++) if(*s == '/') last = s+1; safestrcpy(proc->name, last, sizeof(proc->name)); // Commit to the user image. oldpgdir = proc->pgdir; proc->pgdir = pgdir; proc->sz = sz; proc->tf->eip = elf.entry; // main proc->tf->esp = sp; switchuvm(proc); freevm(oldpgdir); return 0; bad: if(pgdir) freevm(pgdir); iunlockput(ip); return -1; }