diff --git a/exec.c b/exec.c
index 4da73b26767971ac42c1040e895ef201b5a194fd..9f06605e5ae6114780474b5851eb407fd1ed0e74 100644
--- a/exec.c
+++ b/exec.c
@@ -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;
 }