Index: libexec/rtld-elf-cap/rtld-elf-cap.xs
===================================================================
--- libexec/rtld-elf-cap/rtld-elf-cap.xs	(revision 198082)
+++ libexec/rtld-elf-cap/rtld-elf-cap.xs	(working copy)
@@ -5,9 +5,9 @@
  * XXXRW: Is there a way to override the executable start using the base
  * script without a custom one?
  */
-OUTPUT_FORMAT("elf32-i386-freebsd", "elf32-i386-freebsd",
-	      "elf32-i386-freebsd")
-OUTPUT_ARCH(i386)
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
+	      "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
 ENTRY(_start)
 SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
 /* Do we need any of these for elf?
@@ -69,12 +69,12 @@
   .eh_frame_hdr : { *(.eh_frame_hdr) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
-  . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1)); . = DATA_SEGMENT_ALIGN (0x1000, 0x1000);
+  . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000);
   /* Ensure the __preinit_array_start label is properly aligned.  We
      could instead move the label definition inside the section, but
      the linker would then create the section even if it turns out to
      be empty, which isn't pretty.  */
-  . = ALIGN(32 / 8);
+  . = ALIGN(64 / 8);
   .preinit_array     : { *(.preinit_array) }
   .init_array     : { *(.init_array) }
   .fini_array     : { *(.fini_array) }
@@ -129,9 +129,9 @@
    /* Align here to ensure that the .bss section occupies space up to
       _end.  Align after .bss to ensure correct alignment even if the
       .bss section disappears because there are no input sections.  */
-   . = ALIGN(32 / 8);
+   . = ALIGN(64 / 8);
   }
-  . = ALIGN(32 / 8);
+  . = ALIGN(64 / 8);
   _end = .;
   PROVIDE (end = .);
   . = DATA_SEGMENT_END (.);
Index: libexec/rtld-elf-cap/Makefile
===================================================================
--- libexec/rtld-elf-cap/Makefile	(revision 198082)
+++ libexec/rtld-elf-cap/Makefile	(working copy)
@@ -20,7 +20,7 @@
 BINDIR=		/libexec
 MLINKS=		rtld-elf-cap.1 ld-elf-cap.so.1.1
 
-CFLAGS+=	-fpic -DPIC
+CFLAGS+=	-fpic -DPIC -g
 LDFLAGS+=	-shared -Wl,-Bsymbolic
 DPADD=		${LIBC_PIC}
 LDADD=		-lc_pic
Index: libexec/rtld-elf/rtld.c
===================================================================
--- libexec/rtld-elf/rtld.c	(revision 198082)
+++ libexec/rtld-elf/rtld.c	(working copy)
@@ -555,6 +555,7 @@
     /* Initialize a fake symbol for resolving undefined weak references. */
     sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
     sym_zero.st_shndx = SHN_UNDEF;
+    sym_zero.st_value = -(uintptr_t)obj_main->relocbase;
 
 #ifdef IN_RTLD_CAP
     if (ld_caplibindex != NULL)
@@ -1114,26 +1115,26 @@
 
     obj = obj_new();
     for (ph = phdr;  ph < phlimit;  ph++) {
+	if (ph->p_type != PT_PHDR)
+	    continue;
+
+	obj->phdr = phdr;
+	obj->phsize = ph->p_memsz;
+	obj->relocbase = (caddr_t)phdr - ph->p_vaddr;
+	break;
+    }
+
+    for (ph = phdr;  ph < phlimit;  ph++) {
 	switch (ph->p_type) {
 
-	case PT_PHDR:
-	    if ((const Elf_Phdr *)ph->p_vaddr != phdr) {
-		_rtld_error("%s: invalid PT_PHDR", path);
-		return NULL;
-	    }
-	    obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
-	    obj->phsize = ph->p_memsz;
-	    break;
-
 	case PT_INTERP:
-	    obj->interp = (const char *) ph->p_vaddr;
+	    obj->interp = (const char *)(ph->p_vaddr + obj->relocbase);
 	    break;
 
 	case PT_LOAD:
 	    if (nsegs == 0) {	/* First load segment */
 		obj->vaddrbase = trunc_page(ph->p_vaddr);
-		obj->mapbase = (caddr_t) obj->vaddrbase;
-		obj->relocbase = obj->mapbase - obj->vaddrbase;
+		obj->mapbase = obj->vaddrbase + obj->relocbase;
 		obj->textsize = round_page(ph->p_vaddr + ph->p_memsz) -
 		  obj->vaddrbase;
 	    } else {		/* Last load segment */
@@ -1144,7 +1145,7 @@
 	    break;
 
 	case PT_DYNAMIC:
-	    obj->dynamic = (const Elf_Dyn *) ph->p_vaddr;
+	    obj->dynamic = (const Elf_Dyn *)(ph->p_vaddr + obj->relocbase);
 	    break;
 
 	case PT_TLS:
@@ -1152,7 +1153,7 @@
 	    obj->tlssize = ph->p_memsz;
 	    obj->tlsalign = ph->p_align;
 	    obj->tlsinitsize = ph->p_filesz;
-	    obj->tlsinit = (void*) ph->p_vaddr;
+	    obj->tlsinit = (void*)(ph->p_vaddr + obj->relocbase);
 	    break;
 	}
     }
Index: sys/powerpc/include/elf.h
===================================================================
--- sys/powerpc/include/elf.h	(revision 198082)
+++ sys/powerpc/include/elf.h	(working copy)
@@ -96,4 +96,6 @@
 #define	ELF_TARG_MACH	EM_PPC
 #define	ELF_TARG_VER	1
 
+#define	ET_DYN_LOAD_ADDR 0x01010000
+
 #endif /* !_MACHINE_ELF_H_ */
Index: sys/arm/include/elf.h
===================================================================
--- sys/arm/include/elf.h	(revision 198082)
+++ sys/arm/include/elf.h	(working copy)
@@ -97,4 +97,7 @@
  * value.
  */
 #define MAGIC_TRAMP_NUMBER	0x5c000003
+
+#define	ET_DYN_LOAD_ADDR 0x12000
+
 #endif /* !_MACHINE_ELF_H_ */
Index: sys/sparc64/include/elf.h
===================================================================
--- sys/sparc64/include/elf.h	(revision 198082)
+++ sys/sparc64/include/elf.h	(working copy)
@@ -97,4 +97,6 @@
 #define	ELF_TARG_MACH	ELF_ARCH
 #define	ELF_TARG_VER	1
 
+#define	ET_DYN_LOAD_ADDR 0x150000000
+
 #endif /* !_MACHINE_ELF_H_ */
Index: sys/kern/imgact_elf.c
===================================================================
--- sys/kern/imgact_elf.c	(revision 198082)
+++ sys/kern/imgact_elf.c	(working copy)
@@ -637,7 +637,8 @@
 	}
 
 	for (i = 0, numsegs = 0; i < hdr->e_phnum; i++) {
-		if (phdr[i].p_type == PT_LOAD) {	/* Loadable segment */
+		if (phdr[i].p_type == PT_LOAD && phdr[i].p_memsz != 0) {
+			/* Loadable segment */
 			prot = 0;
 			if (phdr[i].p_flags & PF_X)
   				prot |= VM_PROT_EXECUTE;
@@ -689,9 +690,9 @@
 	u_long text_size = 0, data_size = 0, total_size = 0;
 	u_long text_addr = 0, data_addr = 0;
 	u_long seg_size, seg_addr;
-	u_long addr, entry = 0, proghdr = 0;
+	u_long addr, baddr, et_dyn_addr, entry = 0, proghdr = 0;
 	int32_t osrel = 0;
-	int error = 0, i;
+	int error = 0, i, n;
 	const char *interp = NULL, *newinterp = NULL;
 	Elf_Brandinfo *brand_info;
 	char *path;
@@ -720,14 +721,22 @@
 	phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
 	if (!aligned(phdr, Elf_Addr))
 		return (ENOEXEC);
+	n = 0;
+	baddr = 0;
 	for (i = 0; i < hdr->e_phnum; i++) {
+		if (phdr[i].p_type == PT_LOAD) {
+			if (n == 0)
+				baddr = phdr[i].p_vaddr;
+			n++;
+			continue;
+		}
 		if (phdr[i].p_type == PT_INTERP) {
 			/* Path to interpreter */
 			if (phdr[i].p_filesz > MAXPATHLEN ||
 			    phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE)
 				return (ENOEXEC);
 			interp = imgp->image_header + phdr[i].p_offset;
-			break;
+			continue;
 		}
 	}
 
@@ -737,9 +746,19 @@
 		    hdr->e_ident[EI_OSABI]);
 		return (ENOEXEC);
 	}
-	if (hdr->e_type == ET_DYN &&
-	    (brand_info->flags & BI_CAN_EXEC_DYN) == 0)
-		return (ENOEXEC);
+	if (hdr->e_type == ET_DYN) {
+		if ((brand_info->flags & BI_CAN_EXEC_DYN) == 0)
+			return (ENOEXEC);
+		/*
+		 * Honour the base load address from the dso if it is
+		 * non-zero for some reason.
+		 */
+		if (baddr == 0)
+			et_dyn_addr = ET_DYN_LOAD_ADDR;
+		else
+			et_dyn_addr = 0;
+	} else
+		et_dyn_addr = 0;
 	sv = brand_info->sysvec;
 	if (interp != NULL && brand_info->interp_newpath != NULL)
 		newinterp = brand_info->interp_newpath;
@@ -766,6 +785,8 @@
 	for (i = 0; i < hdr->e_phnum; i++) {
 		switch (phdr[i].p_type) {
 		case PT_LOAD:	/* Loadable segment */
+			if (phdr[i].p_memsz == 0)
+				break;
 			prot = 0;
 			if (phdr[i].p_flags & PF_X)
   				prot |= VM_PROT_EXECUTE;
@@ -785,7 +806,7 @@
 
 			if ((error = __elfN(load_section)(vmspace,
 			    imgp->object, phdr[i].p_offset,
-			    (caddr_t)(uintptr_t)phdr[i].p_vaddr,
+			    (caddr_t)(uintptr_t)phdr[i].p_vaddr + et_dyn_addr,
 			    phdr[i].p_memsz, phdr[i].p_filesz, prot,
 			    sv->sv_pagesize)) != 0)
 				return (error);
@@ -799,11 +820,12 @@
 			if (phdr[i].p_offset == 0 &&
 			    hdr->e_phoff + hdr->e_phnum * hdr->e_phentsize
 				<= phdr[i].p_filesz)
-				proghdr = phdr[i].p_vaddr + hdr->e_phoff;
+				proghdr = phdr[i].p_vaddr + hdr->e_phoff +
+				    et_dyn_addr;
 
-			seg_addr = trunc_page(phdr[i].p_vaddr);
+			seg_addr = trunc_page(phdr[i].p_vaddr + et_dyn_addr);
 			seg_size = round_page(phdr[i].p_memsz +
-			    phdr[i].p_vaddr - seg_addr);
+			    phdr[i].p_vaddr + et_dyn_addr - seg_addr);
 
 			/*
 			 * Is this .text or .data?  We can't use
@@ -825,7 +847,7 @@
 			    phdr[i].p_memsz)) {
 				text_size = seg_size;
 				text_addr = seg_addr;
-				entry = (u_long)hdr->e_entry;
+				entry = (u_long)hdr->e_entry + et_dyn_addr;
 			} else {
 				data_size = seg_size;
 				data_addr = seg_addr;
@@ -833,7 +855,7 @@
 			total_size += seg_size;
 			break;
 		case PT_PHDR: 	/* Program header table info */
-			proghdr = phdr[i].p_vaddr;
+			proghdr = phdr[i].p_vaddr + et_dyn_addr;
 			break;
 		default:
 			break;
@@ -905,7 +927,7 @@
 			return (error);
 		}
 	} else
-		addr = 0;
+		addr = et_dyn_addr;
 
 	/*
 	 * Construct auxargs table (used by the fixup routine)
Index: sys/ia64/include/elf.h
===================================================================
--- sys/ia64/include/elf.h	(revision 198082)
+++ sys/ia64/include/elf.h	(working copy)
@@ -141,4 +141,6 @@
 
 #define	DT_IA_64_PLT_RESERVE	0x70000000
 
+#define	ET_DYN_LOAD_ADDR 0x2500000000000000
+
 #endif /* !_MACHINE_ELF_H_ */
Index: sys/mips/include/elf.h
===================================================================
--- sys/mips/include/elf.h	(revision 198082)
+++ sys/mips/include/elf.h	(working copy)
@@ -250,4 +250,6 @@
 
 #define	AT_COUNT	16	/* Count of defined aux entry types. */
 
+#define	ET_DYN_LOAD_ADDR 0x0120000
+
 #endif /* !_MACHINE_ELF_H_ */
Index: sys/sun4v/include/elf.h
===================================================================
--- sys/sun4v/include/elf.h	(revision 198082)
+++ sys/sun4v/include/elf.h	(working copy)
@@ -97,4 +97,6 @@
 #define	ELF_TARG_MACH	ELF_ARCH
 #define	ELF_TARG_VER	1
 
+#define	ET_DYN_LOAD_ADDR 0x150000000
+
 #endif /* !_MACHINE_ELF_H_ */
Index: sys/i386/include/elf.h
===================================================================
--- sys/i386/include/elf.h	(revision 198082)
+++ sys/i386/include/elf.h	(working copy)
@@ -105,4 +105,6 @@
 #define	ELF_TARG_MACH	EM_386
 #define	ELF_TARG_VER	1
 
+#define	ET_DYN_LOAD_ADDR 0x01001000
+
 #endif /* !_MACHINE_ELF_H_ */
Index: sys/amd64/include/elf.h
===================================================================
--- sys/amd64/include/elf.h	(revision 198082)
+++ sys/amd64/include/elf.h	(working copy)
@@ -106,4 +106,10 @@
 #define	ELF_TARG_MACH	EM_X86_64
 #define	ELF_TARG_VER	1
 
+#if __ELF_WORD_SIZE == 32
+#define	ET_DYN_LOAD_ADDR 0x01001000
+#else
+#define	ET_DYN_LOAD_ADDR 0x01021000
+#endif
+
 #endif /* !_MACHINE_ELF_H_ */
