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_ */