diff --git a/Makefile b/Makefile
index d7de428..39a99d7 100644
--- a/Makefile
+++ b/Makefile
@@ -90,7 +90,7 @@ tags: $(OBJS) _init
 ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o
 
 _%: %.o $(ULIB)
-	$(LD) $(LDFLAGS) -verbose -e _main -Ttext 0 -o $@ $^
+	$(LD) $(LDFLAGS) -T $U/user.ld -o $@ $^
 	$(OBJDUMP) -S $@ > $*.asm
 	$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
 
diff --git a/kernel/exec.c b/kernel/exec.c
index aee9345..e18bbb6 100644
--- a/kernel/exec.c
+++ b/kernel/exec.c
@@ -7,7 +7,7 @@
 #include "defs.h"
 #include "elf.h"
 
-static int loadseg(pde_t *, uint64, uint, struct inode *, uint, uint);
+static int loadseg(pde_t *, uint64, struct inode *, uint, uint);
 
 int flags2perm(int flags)
 {
@@ -59,15 +59,13 @@ exec(char *path, char **argv)
       goto bad;
     if(ph.vaddr + ph.memsz < ph.vaddr)
       goto bad;
-    if(ph.align != PGSIZE)
+    if(ph.vaddr % PGSIZE != 0)
       goto bad;
-    uint64 e = PGROUNDUP(ph.vaddr + ph.memsz);
     uint64 sz1;
-    if((sz1 = uvmalloc(pagetable, sz, e, flags2perm(ph.flags))) == 0)
+    if((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz, flags2perm(ph.flags))) == 0)
       goto bad;
     sz = sz1;
-    uint64 s = PGROUNDDOWN(ph.vaddr);
-    if(loadseg(pagetable, s, ph.vaddr - s, ip, ph.off, ph.filesz) < 0)
+    if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
       goto bad;
   }
   iunlockput(ip);
@@ -147,7 +145,7 @@ exec(char *path, char **argv)
 // and the pages from va to va+sz must already be mapped.
 // Returns 0 on success, -1 on failure.
 static int
-loadseg(pagetable_t pagetable, uint64 va, uint poff, struct inode *ip, uint offset, uint sz)
+loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz)
 {
   uint i, n;
   uint64 pa;
@@ -160,7 +158,7 @@ loadseg(pagetable_t pagetable, uint64 va, uint poff, struct inode *ip, uint offs
       n = sz - i;
     else
       n = PGSIZE;
-    if(readi(ip, 0, (uint64)pa+poff, offset+i, n) != n)
+    if(readi(ip, 0, (uint64)pa, offset+i, n) != n)
       return -1;
   }
   
diff --git a/user/user.ld b/user/user.ld
new file mode 100644
index 0000000..0ca922b
--- /dev/null
+++ b/user/user.ld
@@ -0,0 +1,36 @@
+OUTPUT_ARCH( "riscv" )
+ENTRY( _main )
+
+
+SECTIONS
+{
+ . = 0x0;
+ 
+  .text : {
+    *(.text .text.*)
+  }
+
+  .rodata : {
+    . = ALIGN(16);
+    *(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
+    . = ALIGN(16);
+    *(.rodata .rodata.*)
+    . = ALIGN(0x1000);
+  }
+
+  .data : {
+    . = ALIGN(16);
+    *(.sdata .sdata.*) /* do not need to distinguish this from .data */
+    . = ALIGN(16);
+    *(.data .data.*)
+  }
+
+  .bss : {
+    . = ALIGN(16);
+    *(.sbss .sbss.*) /* do not need to distinguish this from .bss */
+    . = ALIGN(16);
+    *(.bss .bss.*)
+  }
+
+  PROVIDE(end = .);
+}