diff options
author | jdp <jdp@FreeBSD.org> | 1999-02-20 23:52:34 +0000 |
---|---|---|
committer | jdp <jdp@FreeBSD.org> | 1999-02-20 23:52:34 +0000 |
commit | 8e6340d9f7c0c2ec6773f8764439f0188bc02b46 (patch) | |
tree | 08fd993acd67c76e1e3534a6e70635924d83b281 | |
parent | 20f2538eb922705ea39b7e7e207e20fa68b3af97 (diff) | |
download | FreeBSD-src-8e6340d9f7c0c2ec6773f8764439f0188bc02b46.zip FreeBSD-src-8e6340d9f7c0c2ec6773f8764439f0188bc02b46.tar.gz |
If you merge this into -stable, please increment __FreeBSD_version
in "src/sys/sys/param.h".
Fix the ELF image activator so that it can handle dynamic linkers
which are executables linked at a fixed address. This improves
compliance with the ABI spec, and it opens the door to possibly
better dynamic linker performance in the future. I've experimented
a bit with a fixed-address dynamic linker, and it works fine. But
I don't have any measurements yet to determine whether it's
worthwhile.
Also, remove a few calculations that were never used for anything.
I will increment __FreeBSD_version, since this adds a new capability
to the kernel that the dynamic linker might some day rely upon.
-rw-r--r-- | sys/kern/imgact_elf.c | 66 |
1 files changed, 38 insertions, 28 deletions
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 4e4478d..8aadb7e 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -26,7 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: imgact_elf.c,v 1.53 1999/02/07 23:49:56 jdp Exp $ + * $Id: imgact_elf.c,v 1.54 1999/02/19 14:25:34 luoqi Exp $ */ #include "opt_rlimit.h" @@ -69,7 +69,7 @@ __ElfType(Brandinfo); __ElfType(Auxargs); -static int elf_check_header __P((const Elf_Ehdr *hdr, int type)); +static int elf_check_header __P((const Elf_Ehdr *hdr)); static int elf_freebsd_fixup __P((long **stack_base, struct image_params *imgp)); static int elf_load_file __P((struct proc *p, char *file, u_long *addr, @@ -165,7 +165,7 @@ elf_brand_inuse(Elf_Brandinfo *entry) } static int -elf_check_header(const Elf_Ehdr *hdr, int type) +elf_check_header(const Elf_Ehdr *hdr) { if (!IS_ELF(*hdr) || hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || @@ -176,7 +176,7 @@ elf_check_header(const Elf_Ehdr *hdr, int type) if (!ELF_MACHINE_OK(hdr->e_machine)) return ENOEXEC; - if (hdr->e_type != type || hdr->e_version != ELF_TARG_VER) + if (hdr->e_version != ELF_TARG_VER) return ENOEXEC; return 0; @@ -295,6 +295,18 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_o return error; } +/* + * Load the file "file" into memory. It may be either a shared object + * or an executable. + * + * The "addr" reference parameter is in/out. On entry, it specifies + * the address where a shared object should be loaded. If the file is + * an executable, this value is ignored. On exit, "addr" specifies + * where the file was actually loaded. + * + * The "entry" reference parameter is out only. On exit, it specifies + * the entry point for the loaded file. + */ static int elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) { @@ -305,9 +317,9 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) struct vattr attr; struct image_params image_params, *imgp; vm_prot_t prot; - unsigned long text_size = 0, data_size = 0; - unsigned long text_addr = 0, data_addr = 0; - int error, i; + u_long rbase; + u_long base_addr = 0; + int error, i, numsegs; imgp = &image_params; /* @@ -349,8 +361,16 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) goto fail; hdr = (const Elf_Ehdr *)imgp->image_header; - if ((error = elf_check_header(hdr, ET_DYN)) != 0) + if ((error = elf_check_header(hdr)) != 0) + goto fail; + if (hdr->e_type == ET_DYN) + rbase = *addr; + else if (hdr->e_type == ET_EXEC) + rbase = 0; + else { + error = ENOEXEC; goto fail; + } /* Only support headers that fit within first page for now */ if ((hdr->e_phoff > PAGE_SIZE) || @@ -361,7 +381,7 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); - for (i = 0; i < hdr->e_phnum; i++) { + for (i = 0, numsegs = 0; i < hdr->e_phnum; i++) { if (phdr[i].p_type == PT_LOAD) { /* Loadable segment */ prot = 0; if (phdr[i].p_flags & PF_X) @@ -374,31 +394,21 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) if ((error = elf_load_section(p, vmspace, nd.ni_vp, phdr[i].p_offset, (caddr_t)phdr[i].p_vaddr + - (*addr), + rbase, phdr[i].p_memsz, phdr[i].p_filesz, prot)) != 0) goto fail; - /* - * Is this .text or .data ?? - * - * We only handle one each of those yet XXX + * Establish the base address if this is the + * first segment. */ - if (hdr->e_entry >= phdr[i].p_vaddr && - hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { - text_addr = trunc_page(phdr[i].p_vaddr+(*addr)); - text_size = round_page(phdr[i].p_memsz + - phdr[i].p_vaddr - - trunc_page(phdr[i].p_vaddr)); - *entry=(unsigned long)hdr->e_entry+(*addr); - } else { - data_addr = trunc_page(phdr[i].p_vaddr+(*addr)); - data_size = round_page(phdr[i].p_memsz + - phdr[i].p_vaddr - - trunc_page(phdr[i].p_vaddr)); - } + if (numsegs == 0) + base_addr = trunc_page(phdr[i].p_vaddr + rbase); + numsegs++; } } + *addr = base_addr; + *entry=(unsigned long)hdr->e_entry + rbase; fail: if (imgp->firstpage) @@ -437,7 +447,7 @@ exec_elf_imgact(struct image_params *imgp) /* * Do we have a valid ELF header ? */ - if (elf_check_header(hdr, ET_EXEC)) + if (elf_check_header(hdr) != 0 || hdr->e_type != ET_EXEC) return -1; /* |