diff options
Diffstat (limited to 'libexec/rtld-elf')
-rw-r--r-- | libexec/rtld-elf/Makefile | 20 | ||||
-rw-r--r-- | libexec/rtld-elf/alpha/reloc.c | 309 | ||||
-rw-r--r-- | libexec/rtld-elf/alpha/rtld_start.S | 169 | ||||
-rw-r--r-- | libexec/rtld-elf/amd64/reloc.c | 236 | ||||
-rw-r--r-- | libexec/rtld-elf/amd64/rtld_start.S | 13 | ||||
-rw-r--r-- | libexec/rtld-elf/i386/reloc.c | 236 | ||||
-rw-r--r-- | libexec/rtld-elf/i386/rtld_start.S | 13 | ||||
-rw-r--r-- | libexec/rtld-elf/malloc.c | 11 | ||||
-rw-r--r-- | libexec/rtld-elf/map_object.c | 56 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.c | 336 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.h | 23 |
11 files changed, 1145 insertions, 277 deletions
diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile index f206711..e565161 100644 --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -1,17 +1,25 @@ # -# $Id: Makefile,v 1.2 1998/04/30 07:47:58 dfr Exp $ +# $Id: Makefile,v 1.3 1998/08/17 04:59:15 jdp Exp $ # PROG= ld-elf.so.1 -SRCS= rtld_start.S rtld.c map_object.c malloc.c xmalloc.c debug.c +SRCS= rtld_start.S rtld.c map_object.c malloc.c xmalloc.c debug.c \ + reloc.c NOMAN= true -CFLAGS+= -elf -fpic -DFREEBSD_ELF -CFLAGS+= -Wall -LDFLAGS+= -elf -nostdlib -Wl,-Bshareable,-Bsymbolic +CFLAGS+= -fpic -Wall -DFREEBSD_ELF -I${.CURDIR} LDADD+= -lc_pic + +.if ${MACHINE_ARCH} == "alpha" +CFLAGS+= -mno-fp-regs +LDFLAGS+= -nostdlib -Wl,-Bshareable,-Bsymbolic -e .rtld_start +.elif ${MACHINE_ARCH} == "i386" +CFLAGS+= -elf +LDFLAGS+= -elf -nostdlib -Wl,-Bshareable,-Bsymbolic +.endif + # Atomic installation with "-C" is very important for this program. INSTALLFLAGS+= -C -.PATH: ${.CURDIR}/${MACHINE} +.PATH: ${.CURDIR}/${MACHINE_ARCH} .include <bsd.prog.mk> diff --git a/libexec/rtld-elf/alpha/reloc.c b/libexec/rtld-elf/alpha/reloc.c new file mode 100644 index 0000000..e43b12a --- /dev/null +++ b/libexec/rtld-elf/alpha/reloc.c @@ -0,0 +1,309 @@ +/*- + * Copyright 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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: rtld.c,v 1.3 1998/05/01 08:39:27 dfr Exp $ + */ + +/* + * Dynamic linker for ELF. + * + * John Polstra <jdp@polstra.com>. + */ + +#include <sys/param.h> +#include <sys/mman.h> + +#include <dlfcn.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "debug.h" +#include "rtld.h" + +/* + * Debugging support. + */ + +#define assert(cond) ((cond) ? (void) 0 :\ + (msg("oops: " __XSTRING(__LINE__) "\n"), abort())) +#define msg(s) (write(1, s, strlen(s))) +#define trace() msg("trace: " __XSTRING(__LINE__) "\n"); + +extern Elf_Dyn _DYNAMIC; + +/* Relocate a non-PLT object with addend. */ +static int +reloc_non_plt_obj(Obj_Entry *obj_rtld, const Obj_Entry *obj, + const Elf_Rela *rela) +{ + Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset); + + switch (ELF_R_TYPE(rela->r_info)) { + + case R_ALPHA_REFQUAD: { + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr tmp_value; + + def = find_symdef(ELF_R_SYM(rela->r_info), obj, + &defobj, false); + if (def == NULL) + return -1; + + tmp_value = (Elf_Addr) (defobj->relocbase + + def->st_value) + *where + rela->r_addend; + if (*where != tmp_value) + *where = tmp_value; + } + break; + + case R_ALPHA_GLOB_DAT: { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rela->r_info), obj, + &defobj, false); + if (def == NULL) + return -1; + + if (*where != (Elf_Addr) (defobj->relocbase + + def->st_value)) + *where = (Elf_Addr) (defobj->relocbase + + def->st_value); + } + break; + + case R_ALPHA_RELATIVE: { + if (obj != obj_rtld || + (caddr_t)where < (caddr_t)_GLOBAL_OFFSET_TABLE_ || + (caddr_t)where >= (caddr_t)&_DYNAMIC) + *where += (Elf_Addr) obj->relocbase; + } + break; + + case R_ALPHA_COPY: { + /* + * These are deferred until all other relocations + * have been done. All we do here is make sure + * that the COPY relocation is not in a shared + * library. They are allowed only in executable + * files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_COPY " + " relocation in shared library", + obj->path); + return -1; + } + } + break; + + default: + _rtld_error("%s: Unsupported relocation type %d" + " in non-PLT relocations\n", obj->path, + ELF_R_TYPE(rela->r_info)); + return -1; + } + return(0); +} + +/* Process the non-PLT relocations. */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + const Elf_Rela *relalim; + const Elf_Rela *rela; + + /* Perform relocations without addend if there are any: */ + rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize); + for (rel = obj->rel; obj->rel != NULL && rel < rellim; rel++) { + Elf_Rela locrela; + + locrela.r_info = rel->r_info; + locrela.r_offset = rel->r_offset; + locrela.r_addend = 0; + if (reloc_non_plt_obj(obj_rtld, obj, &locrela)) + return -1; + } + + /* Perform relocations with addend if there are any: */ + relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize); + for (rela = obj->rela; obj->rela != NULL && rela < relalim; rela++) { + if (reloc_non_plt_obj(obj_rtld, obj, rela)) + return -1; + } + return 0; +} + +/* Process the PLT relocations. */ +int +reloc_plt(Obj_Entry *obj, bool bind_now) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + const Elf_Rela *relalim; + const Elf_Rela *rela; + + /* Process the PLT relocations without addend if there are any. */ + rellim = (const Elf_Rel *) ((caddr_t) obj->pltrel + obj->pltrelsize); + if (bind_now) { + /* Fully resolve procedure addresses now */ + for (rel = obj->pltrel; obj->pltrel != NULL && rel < rellim; + rel++) { + Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset); + const Elf_Sym *def; + const Obj_Entry *defobj; + + assert(ELF_R_TYPE(rel->r_info) == R_ALPHA_JMP_SLOT); + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true); + if (def == NULL) + return -1; + + *where = (Elf_Addr) (defobj->relocbase + def->st_value); + } + } else { /* Just relocate the GOT slots pointing into the PLT */ + for (rel = obj->pltrel; obj->pltrel != NULL && rel < rellim; + rel++) { + Elf_Addr *where = (Elf_Addr *) + (obj->relocbase + rel->r_offset); + *where += (Elf_Addr) obj->relocbase; + } + } + + /* Process the PLT relocations with addend if there are any. */ + relalim = (const Elf_Rela *) ((caddr_t) obj->pltrela + + obj->pltrelasize); + if (bind_now) { + /* Fully resolve procedure addresses now */ + for (rela = obj->pltrela; obj->pltrela != NULL && rela < relalim; + rel++) { + Elf_Addr *where = (Elf_Addr *) (obj->relocbase + + rela->r_offset); + const Elf_Sym *def; + const Obj_Entry *defobj; + + assert(ELF_R_TYPE(rela->r_info) == R_ALPHA_JMP_SLOT); + + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true); + if (def == NULL) + return -1; + + *where = (Elf_Addr) (defobj->relocbase + def->st_value); + } + } else { /* Just relocate the GOT slots pointing into the PLT */ + for (rela = obj->pltrela; obj->pltrela != NULL && rela < relalim; + rela++) { + Elf_Addr *where = (Elf_Addr *) + (obj->relocbase + rela->r_offset); + *where += (Elf_Addr) obj->relocbase; + } + } + return 0; +} + +/* Process an R_ALPHA_COPY relocation. */ +static int +do_copy_relocation(Obj_Entry *dstobj, const Elf_Rela *rela) +{ + void *dstaddr; + const Elf_Sym *dstsym; + const char *name; + unsigned long hash; + size_t size; + const void *srcaddr; + const Elf_Sym *srcsym; + Obj_Entry *srcobj; + + dstaddr = (void *) (dstobj->relocbase + rela->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); + name = dstobj->strtab + dstsym->st_name; + hash = elf_hash(name); + size = dstsym->st_size; + + for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) + if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL) + break; + + if (srcobj == NULL) { + _rtld_error("Undefined symbol \"%s\" referenced from COPY" + " relocation in %s", name, dstobj->path); + return -1; + } + + srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + return 0; +} + +/* + * Process the special R_ALPHA_COPY relocations in the main program. These + * copy data from a shared object into a region in the main program's BSS + * segment. + * + * Returns 0 on success, -1 on failure. + */ +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + const Elf_Rela *relalim; + const Elf_Rela *rela; + + assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ + + rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); + for (rel = dstobj->rel; dstobj->rel != NULL && rel < rellim; rel++) { + if (ELF_R_TYPE(rel->r_info) == R_ALPHA_COPY) { + Elf_Rela locrela; + + locrela.r_info = rel->r_info; + locrela.r_offset = rel->r_offset; + locrela.r_addend = 0; + if (do_copy_relocation(dstobj, &locrela)) + return -1; + } + } + + relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + + dstobj->relasize); + for (rela = dstobj->rela; dstobj->rela != NULL && rela < relalim; + rela++) { + if (ELF_R_TYPE(rela->r_info) == R_ALPHA_COPY) { + if (do_copy_relocation(dstobj, rela)) + return -1; + } + } + + return 0; +} diff --git a/libexec/rtld-elf/alpha/rtld_start.S b/libexec/rtld-elf/alpha/rtld_start.S new file mode 100644 index 0000000..e93829f --- /dev/null +++ b/libexec/rtld-elf/alpha/rtld_start.S @@ -0,0 +1,169 @@ +/* $Id$ */ +/* From: NetBSD: rtld_start.S,v 1.1 1996/12/16 20:38:09 cgd Exp */ + +/* + * Copyright 1996 Matt Thomas <matt@3am-software.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <machine/asm.h> +#include <machine/pal.h> + +.extern _GLOBAL_OFFSET_TABLE_ + +LEAF(_rtld_start, 0) /* XXX */ + .set noreorder + br pv, $33 +$33: LDGP(pv) + + /* save away the stack pointer */ + + lda s0, 0(sp) /* get argc from stack */ + lda sp, -16(sp) /* space for arguments */ + + /* save ps_strings pointer */ + mov a3, s1 + + /* Step 1 -- Figure out the displacement */ + + br t2, $34 /* get our PC */ +$34: ldiq t3, $34 /* get where the linker thought we were */ + subq t2, t3, t8 /* calculate the displacement */ + + + /* Step 2 -- Find bounds of global offset table */ + + lda t5, _GLOBAL_OFFSET_TABLE_ + addq t8, t5, t9 /* add the displacement */ + lda t4, _DYNAMIC + addq t8, t4, t10 /* add the displacement */ + + /* + * Step 3 -- Every entry in the global offset table needs to + * modified for the displacement before any code will work. + */ + +$35: ldq t1, 0(t9) /* load the value */ + addq t8, t1, t1 /* add the displacement */ + stq t1, 0(t9) /* save the new value */ + lda t9, 8(t9) /* point to next entry */ + cmpult t9, t10, t1 /* are we done? */ + bne t1, $35 /* no, do more */ + + /* + * Ya! Things are far enough so we can do some dynamic linking! + */ + + lda a0, 0(s0) /* initial sp */ + lda a1, -16(s0) /* address for exit proc */ + lda a2, -8(s0) /* address for obj_main */ + CALL(_rtld) /* v0 = _rtld(sp, &exit_proc, &obj_main); */ + + ldq a1, -16(s0) /* our atexit function */ + ldq a2, -8(s0) /* obj_main entry */ + lda sp, 16(sp) /* readjust our stack */ + mov s0, a0 /* stack pointer */ + mov s1, a3 /* ps_strings pointer */ + mov v0, t12 + jsr ra, (v0), 0 /* (*_start)(sp, cleanup, obj); */ + ldgp gp, 0(ra) + + CALL(exit) + halt +END(_rtld_start) + + .set noat + .globl _rtld_bind_start + .ent _rtld_bind_start +_rtld_bind_start: + + lda sp, -168(sp) + .frame sp, 168, $26 + /* Preserve all registers that C normally doesn't. */ + stq $26, 0(sp) + stq $0, 8(sp) + stq $1, 16(sp) + stq $2, 24(sp) + stq $3, 32(sp) + stq $4, 40(sp) + stq $5, 48(sp) + stq $6, 56(sp) + stq $7, 64(sp) + stq $8, 72(sp) + stq $16, 80(sp) + stq $17, 88(sp) + stq $18, 96(sp) + stq $19, 104(sp) + stq $20, 112(sp) + stq $21, 120(sp) + stq $22, 128(sp) + stq $23, 136(sp) + stq $24, 144(sp) + stq $25, 152(sp) + stq $29, 160(sp) + .mask 0x27ff01ff, -168 + /* Set up our $gp */ + br gp, $100 +$100: ldgp gp, 0(gp) + .prologue 1 + /* Set up the arguments for _rtld_bind. */ + ldq a0, 8(t12) /* object structure */ + mov at_reg, a1 /* offset of reloc entry */ + CALL(_rtld_bind) + + /* Move the destination address into position. */ + mov $0, $27 + /* Restore program registers. */ + ldq $26, 0(sp) + ldq $0, 8(sp) + ldq $1, 16(sp) + ldq $2, 24(sp) + ldq $3, 32(sp) + ldq $4, 40(sp) + ldq $5, 48(sp) + ldq $6, 56(sp) + ldq $7, 64(sp) + ldq $8, 72(sp) + ldq $16, 80(sp) + ldq $17, 88(sp) + ldq $18, 96(sp) + ldq $19, 104(sp) + ldq $20, 112(sp) + ldq $21, 120(sp) + ldq $22, 128(sp) + ldq $23, 136(sp) + ldq $24, 144(sp) + ldq $25, 152(sp) + ldq $29, 160(sp) + /* Flush the Icache after having modified the .plt code. */ + imb + /* Clean up and turn control to the destination */ + lda sp, 168(sp) + jmp $31, ($27) + .end _rtld_bind_start + + + + diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c new file mode 100644 index 0000000..d34d892 --- /dev/null +++ b/libexec/rtld-elf/amd64/reloc.c @@ -0,0 +1,236 @@ +/*- + * Copyright 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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: rtld.c,v 1.3 1998/05/01 08:39:27 dfr Exp $ + */ + +/* + * Dynamic linker for ELF. + * + * John Polstra <jdp@polstra.com>. + */ + +#include <sys/param.h> +#include <sys/mman.h> + +#include <dlfcn.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "debug.h" +#include "rtld.h" + +/* + * Debugging support. + */ + +#define assert(cond) ((cond) ? (void) 0 :\ + (msg("oops: " __XSTRING(__LINE__) "\n"), abort())) +#define msg(s) (write(1, s, strlen(s))) +#define trace() msg("trace: " __XSTRING(__LINE__) "\n"); + +/* + * Process the special R_386_COPY relocations in the main program. These + * copy data from a shared object into a region in the main program's BSS + * segment. + * + * Returns 0 on success, -1 on failure. + */ +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ + + rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); + for (rel = dstobj->rel; rel < rellim; rel++) { + if (ELF_R_TYPE(rel->r_info) == R_386_COPY) { + void *dstaddr; + const Elf_Sym *dstsym; + const char *name; + unsigned long hash; + size_t size; + const void *srcaddr; + const Elf_Sym *srcsym; + Obj_Entry *srcobj; + + dstaddr = (void *) (dstobj->relocbase + rel->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); + name = dstobj->strtab + dstsym->st_name; + hash = elf_hash(name); + size = dstsym->st_size; + + for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) + if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL) + break; + + if (srcobj == NULL) { + _rtld_error("Undefined symbol \"%s\" referenced from COPY" + " relocation in %s", name, dstobj->path); + return -1; + } + + srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + } + + return 0; +} + +/* Process the non-PLT relocations. */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize); + for (rel = obj->rel; rel < rellim; rel++) { + Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset); + + switch (ELF_R_TYPE(rel->r_info)) { + + case R_386_NONE: + break; + + case R_386_32: + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false); + if (def == NULL) + return -1; + + *where += (Elf_Addr) (defobj->relocbase + def->st_value); + } + break; + + case R_386_PC32: + /* + * I don't think the dynamic linker should ever see this + * type of relocation. But the binutils-2.6 tools sometimes + * generate it. + */ + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false); + if (def == NULL) + return -1; + + *where += + (Elf_Addr) (defobj->relocbase + def->st_value) - + (Elf_Addr) where; + } + break; + + case R_386_COPY: + /* + * These are deferred until all other relocations have + * been done. All we do here is make sure that the COPY + * relocation is not in a shared library. They are allowed + * only in executable files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_386_COPY relocation" + " in shared library", obj->path); + return -1; + } + break; + + case R_386_GLOB_DAT: + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false); + if (def == NULL) + return -1; + + *where = (Elf_Addr) (defobj->relocbase + def->st_value); + } + break; + + case R_386_RELATIVE: + *where += (Elf_Addr) obj->relocbase; + break; + + default: + _rtld_error("%s: Unsupported relocation type %d" + " in non-PLT relocations\n", obj->path, + ELF_R_TYPE(rel->r_info)); + return -1; + } + } + return 0; +} + +/* Process the PLT relocations. */ +int +reloc_plt(Obj_Entry *obj, bool bind_now) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + /* Process the PLT relocations. */ + rellim = (const Elf_Rel *) ((caddr_t) obj->pltrel + obj->pltrelsize); + if (bind_now) { + /* Fully resolve procedure addresses now */ + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where = (Elf_Addr *) + (obj->relocbase + rel->r_offset); + const Elf_Sym *def; + const Obj_Entry *defobj; + + assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT); + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true); + if (def == NULL) + return -1; + + *where = (Elf_Addr) (defobj->relocbase + def->st_value); + } + } else { /* Just relocate the GOT slots pointing into the PLT */ + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where = (Elf_Addr *) + (obj->relocbase + rel->r_offset); + *where += (Elf_Addr) obj->relocbase; + } + } + return 0; +} diff --git a/libexec/rtld-elf/amd64/rtld_start.S b/libexec/rtld-elf/amd64/rtld_start.S index f82e564..d678f2e 100644 --- a/libexec/rtld-elf/amd64/rtld_start.S +++ b/libexec/rtld-elf/amd64/rtld_start.S @@ -22,7 +22,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: rtld_start.S,v 1.6 1998/03/05 21:05:53 jdp Exp $ + * $Id: rtld_start.S,v 1.1.1.1 1998/03/07 19:24:35 jdp Exp $ */ .text @@ -32,12 +32,17 @@ .rtld_start: xorl %ebp,%ebp # Clear frame pointer for good form movl %esp,%eax # Save initial stack pointer - subl $4,%esp # A place to store exit procedure addr - pushl %esp # Pass its address to rtld + subl $8,%esp # A place to store exit procedure addr + movl %esp,%ebx # save address of exit proc + movl %esp,%ecx # construct address of obj_main + addl $4,%ecx + pushl %ecx # Pass address of obj_main + pushl %ebx # Pass address of exit proc pushl %eax # Pass initial stack pointer to rtld call _rtld@PLT # Call rtld(sp); returns entry point - addl $8,%esp # Remove arguments from stack + addl $12,%esp # Remove arguments from stack popl %edx # Get exit procedure address + addl $4,%esp # Ignore obj_main /* * At this point, %eax contains the entry point of the main program, and * %edx contains a pointer to a termination function that should be diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c new file mode 100644 index 0000000..d34d892 --- /dev/null +++ b/libexec/rtld-elf/i386/reloc.c @@ -0,0 +1,236 @@ +/*- + * Copyright 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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: rtld.c,v 1.3 1998/05/01 08:39:27 dfr Exp $ + */ + +/* + * Dynamic linker for ELF. + * + * John Polstra <jdp@polstra.com>. + */ + +#include <sys/param.h> +#include <sys/mman.h> + +#include <dlfcn.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "debug.h" +#include "rtld.h" + +/* + * Debugging support. + */ + +#define assert(cond) ((cond) ? (void) 0 :\ + (msg("oops: " __XSTRING(__LINE__) "\n"), abort())) +#define msg(s) (write(1, s, strlen(s))) +#define trace() msg("trace: " __XSTRING(__LINE__) "\n"); + +/* + * Process the special R_386_COPY relocations in the main program. These + * copy data from a shared object into a region in the main program's BSS + * segment. + * + * Returns 0 on success, -1 on failure. + */ +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ + + rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); + for (rel = dstobj->rel; rel < rellim; rel++) { + if (ELF_R_TYPE(rel->r_info) == R_386_COPY) { + void *dstaddr; + const Elf_Sym *dstsym; + const char *name; + unsigned long hash; + size_t size; + const void *srcaddr; + const Elf_Sym *srcsym; + Obj_Entry *srcobj; + + dstaddr = (void *) (dstobj->relocbase + rel->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); + name = dstobj->strtab + dstsym->st_name; + hash = elf_hash(name); + size = dstsym->st_size; + + for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) + if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL) + break; + + if (srcobj == NULL) { + _rtld_error("Undefined symbol \"%s\" referenced from COPY" + " relocation in %s", name, dstobj->path); + return -1; + } + + srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + } + + return 0; +} + +/* Process the non-PLT relocations. */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize); + for (rel = obj->rel; rel < rellim; rel++) { + Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset); + + switch (ELF_R_TYPE(rel->r_info)) { + + case R_386_NONE: + break; + + case R_386_32: + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false); + if (def == NULL) + return -1; + + *where += (Elf_Addr) (defobj->relocbase + def->st_value); + } + break; + + case R_386_PC32: + /* + * I don't think the dynamic linker should ever see this + * type of relocation. But the binutils-2.6 tools sometimes + * generate it. + */ + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false); + if (def == NULL) + return -1; + + *where += + (Elf_Addr) (defobj->relocbase + def->st_value) - + (Elf_Addr) where; + } + break; + + case R_386_COPY: + /* + * These are deferred until all other relocations have + * been done. All we do here is make sure that the COPY + * relocation is not in a shared library. They are allowed + * only in executable files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_386_COPY relocation" + " in shared library", obj->path); + return -1; + } + break; + + case R_386_GLOB_DAT: + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false); + if (def == NULL) + return -1; + + *where = (Elf_Addr) (defobj->relocbase + def->st_value); + } + break; + + case R_386_RELATIVE: + *where += (Elf_Addr) obj->relocbase; + break; + + default: + _rtld_error("%s: Unsupported relocation type %d" + " in non-PLT relocations\n", obj->path, + ELF_R_TYPE(rel->r_info)); + return -1; + } + } + return 0; +} + +/* Process the PLT relocations. */ +int +reloc_plt(Obj_Entry *obj, bool bind_now) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + /* Process the PLT relocations. */ + rellim = (const Elf_Rel *) ((caddr_t) obj->pltrel + obj->pltrelsize); + if (bind_now) { + /* Fully resolve procedure addresses now */ + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where = (Elf_Addr *) + (obj->relocbase + rel->r_offset); + const Elf_Sym *def; + const Obj_Entry *defobj; + + assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT); + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true); + if (def == NULL) + return -1; + + *where = (Elf_Addr) (defobj->relocbase + def->st_value); + } + } else { /* Just relocate the GOT slots pointing into the PLT */ + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where = (Elf_Addr *) + (obj->relocbase + rel->r_offset); + *where += (Elf_Addr) obj->relocbase; + } + } + return 0; +} diff --git a/libexec/rtld-elf/i386/rtld_start.S b/libexec/rtld-elf/i386/rtld_start.S index f82e564..d678f2e 100644 --- a/libexec/rtld-elf/i386/rtld_start.S +++ b/libexec/rtld-elf/i386/rtld_start.S @@ -22,7 +22,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: rtld_start.S,v 1.6 1998/03/05 21:05:53 jdp Exp $ + * $Id: rtld_start.S,v 1.1.1.1 1998/03/07 19:24:35 jdp Exp $ */ .text @@ -32,12 +32,17 @@ .rtld_start: xorl %ebp,%ebp # Clear frame pointer for good form movl %esp,%eax # Save initial stack pointer - subl $4,%esp # A place to store exit procedure addr - pushl %esp # Pass its address to rtld + subl $8,%esp # A place to store exit procedure addr + movl %esp,%ebx # save address of exit proc + movl %esp,%ecx # construct address of obj_main + addl $4,%ecx + pushl %ecx # Pass address of obj_main + pushl %ebx # Pass address of exit proc pushl %eax # Pass initial stack pointer to rtld call _rtld@PLT # Call rtld(sp); returns entry point - addl $8,%esp # Remove arguments from stack + addl $12,%esp # Remove arguments from stack popl %edx # Get exit procedure address + addl $4,%esp # Ignore obj_main /* * At this point, %eax contains the entry point of the main program, and * %edx contains a pointer to a termination function that should be diff --git a/libexec/rtld-elf/malloc.c b/libexec/rtld-elf/malloc.c index a451700..6689796 100644 --- a/libexec/rtld-elf/malloc.c +++ b/libexec/rtld-elf/malloc.c @@ -33,7 +33,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/ -static char *rcsid = "$Id: malloc.c,v 1.2 1996/01/19 18:36:54 jdp Exp $"; +static char *rcsid = "$Id: malloc.c,v 1.1.1.1 1998/03/07 19:24:35 jdp Exp $"; #endif /* LIBC_SCCS and not lint */ /* @@ -156,7 +156,8 @@ malloc(nbytes) size_t nbytes; { register union overhead *op; - register int bucket, n; + register int bucket; + register long n; register unsigned amt; /* @@ -168,7 +169,7 @@ malloc(nbytes) if (morepages(NPOOLPAGES) == 0) return NULL; op = (union overhead *)(pagepool_start); - n = n - sizeof (*op) - ((int)op & (n - 1)); + n = n - sizeof (*op) - ((long)op & (n - 1)); if (n < 0) n += pagesz; if (n) { @@ -462,12 +463,12 @@ int n; if (pagepool_end - pagepool_start > pagesz) { caddr_t addr = (caddr_t) - (((int)pagepool_start + pagesz - 1) & ~(pagesz - 1)); + (((long)pagepool_start + pagesz - 1) & ~(pagesz - 1)); if (munmap(addr, pagepool_end - addr) != 0) warn("morepages: munmap %p", addr); } - offset = (int)pagepool_start - ((int)pagepool_start & ~(pagesz - 1)); + offset = (long)pagepool_start - ((long)pagepool_start & ~(pagesz - 1)); if ((pagepool_start = mmap(0, n * pagesz, PROT_READ|PROT_WRITE, diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index 0e33b3c..a393bb8 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -22,7 +22,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: map_object.c,v 1.2 1998/03/06 22:14:53 jdp Exp $ + * $Id: map_object.c,v 1.1.1.1 1998/03/07 19:24:35 jdp Exp $ */ #include <sys/param.h> @@ -50,31 +50,31 @@ map_object(int fd) { Obj_Entry *obj; union { - Elf32_Ehdr hdr; + Elf_Ehdr hdr; char buf[PAGE_SIZE]; } u; int nbytes; - Elf32_Phdr *phdr; - Elf32_Phdr *phlimit; - Elf32_Phdr *segs[2]; + Elf_Phdr *phdr; + Elf_Phdr *phlimit; + Elf_Phdr *segs[2]; int nsegs; - Elf32_Phdr *phdyn; - Elf32_Phdr *phphdr; + Elf_Phdr *phdyn; + Elf_Phdr *phphdr; caddr_t mapbase; size_t mapsize; - Elf32_Off base_offset; - Elf32_Addr base_vaddr; - Elf32_Addr base_vlimit; + Elf_Off base_offset; + Elf_Addr base_vaddr; + Elf_Addr base_vlimit; caddr_t base_addr; - Elf32_Off data_offset; - Elf32_Addr data_vaddr; - Elf32_Addr data_vlimit; + Elf_Off data_offset; + Elf_Addr data_vaddr; + Elf_Addr data_vlimit; caddr_t data_addr; - Elf32_Addr clear_vaddr; + Elf_Addr clear_vaddr; caddr_t clear_addr; size_t nclear; - Elf32_Addr bss_vaddr; - Elf32_Addr bss_vlimit; + Elf_Addr bss_vaddr; + Elf_Addr bss_vlimit; caddr_t bss_addr; if ((nbytes = read(fd, u.buf, PAGE_SIZE)) == -1) { @@ -83,7 +83,7 @@ map_object(int fd) } /* Make sure the file is valid */ - if (nbytes < sizeof(Elf32_Ehdr) + if (nbytes < sizeof(Elf_Ehdr) || u.hdr.e_ident[EI_MAG0] != ELFMAG0 || u.hdr.e_ident[EI_MAG1] != ELFMAG1 || u.hdr.e_ident[EI_MAG2] != ELFMAG2 @@ -91,8 +91,8 @@ map_object(int fd) _rtld_error("Invalid file format"); return NULL; } - if (u.hdr.e_ident[EI_CLASS] != ELFCLASS32 - || u.hdr.e_ident[EI_DATA] != ELFDATA2LSB) { + if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS + || u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) { _rtld_error("Unsupported file layout"); return NULL; } @@ -105,7 +105,7 @@ map_object(int fd) _rtld_error("Unsupported file type"); return NULL; } - if (u.hdr.e_machine != EM_386) { + if (u.hdr.e_machine != ELF_TARG_MACH) { _rtld_error("Unsupported machine"); return NULL; } @@ -115,9 +115,9 @@ map_object(int fd) * not strictly required by the ABI specification, but it seems to * always true in practice. And, it simplifies things considerably. */ - assert(u.hdr.e_phentsize == sizeof(Elf32_Phdr)); - assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf32_Phdr) <= PAGE_SIZE); - assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf32_Phdr) <= nbytes); + assert(u.hdr.e_phentsize == sizeof(Elf_Phdr)); + assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE); + assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= nbytes); /* * Scan the program header entries, and save key information. @@ -125,7 +125,7 @@ map_object(int fd) * We rely on there being exactly two load segments, text and data, * in that order. */ - phdr = (Elf32_Phdr *) (u.buf + u.hdr.e_phoff); + phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff); phlimit = phdr + u.hdr.e_phnum; nsegs = 0; phdyn = NULL; @@ -156,8 +156,8 @@ map_object(int fd) } assert(nsegs == 2); - assert(segs[0]->p_align <= PAGE_SIZE); - assert(segs[1]->p_align <= PAGE_SIZE); + assert(segs[0]->p_align >= PAGE_SIZE); + assert(segs[1]->p_align >= PAGE_SIZE); /* * Map the entire address space of the object, to stake out our @@ -219,12 +219,12 @@ map_object(int fd) base_vaddr; obj->vaddrbase = base_vaddr; obj->relocbase = mapbase - base_vaddr; - obj->dynamic = (const Elf32_Dyn *) + obj->dynamic = (const Elf_Dyn *) (mapbase + (phdyn->p_vaddr - base_vaddr)); if (u.hdr.e_entry != 0) obj->entry = (caddr_t) (mapbase + (u.hdr.e_entry - base_vaddr)); if (phphdr != NULL) { - obj->phdr = (const Elf32_Phdr *) + obj->phdr = (const Elf_Phdr *) (mapbase + (phphdr->p_vaddr - base_vaddr)); obj->phsize = phphdr->p_memsz; } diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 9decc12..c52efa0 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -22,7 +22,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: rtld.c,v 1.5 1998/09/02 02:00:20 jdp Exp $ + * $Id: rtld.c,v 1.6 1998/09/02 02:51:12 jdp Exp $ */ /* @@ -72,15 +72,11 @@ static void call_fini_functions(Obj_Entry *); static void call_init_functions(Obj_Entry *); static void die(void); static void digest_dynamic(Obj_Entry *); -static Obj_Entry *digest_phdr(const Elf32_Phdr *, int, caddr_t); +static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t); static Obj_Entry *dlcheck(void *); -static int do_copy_relocations(Obj_Entry *); -static unsigned long elf_hash(const char *); static char *find_library(const char *, const Obj_Entry *); -static const Elf32_Sym *find_symdef(unsigned long, const Obj_Entry *, - const Obj_Entry **, bool); static void init_rtld(caddr_t); -static bool is_exported(const Elf32_Sym *); +static bool is_exported(const Elf_Sym *); static void linkmap_add(Obj_Entry *); static void linkmap_delete(Obj_Entry *); static int load_needed_objects(Obj_Entry *); @@ -89,8 +85,6 @@ static Obj_Entry *obj_from_addr(const void *); static int relocate_objects(Obj_Entry *, bool); static void rtld_exit(void); static char *search_library_path(const char *, const char *); -static const Elf32_Sym *symlook_obj(const char *, unsigned long, - const Obj_Entry *, bool); static void unref_object_dag(Obj_Entry *); static void trace_loaded_objects(Obj_Entry *obj); @@ -109,11 +103,13 @@ extern void _rtld_bind_start(void); */ #ifdef __i386__ #define get_got_address() \ - ({ Elf32_Addr *thegot; \ + ({ Elf_Addr *thegot; \ __asm__("movl %%ebx,%0" : "=rm"(thegot)); \ thegot; }) +#elif __alpha__ +#define get_got_address() NULL #else -#error "This file only supports the i386 architecture" +#error "This file only supports the i386 and alpha architectures" #endif /* @@ -135,6 +131,8 @@ static Obj_Entry obj_rtld; /* The dynamic linker shared object */ #define GDB_STATE(s) r_debug.r_state = s; r_debug_state(); +extern Elf_Dyn _DYNAMIC; + /* * These are the functions the dynamic linker exports to application * programs. They are the only symbols the dynamic linker is willing @@ -167,20 +165,21 @@ char **environ; * sequence of "auxiliary vector" entries. * * The second argument points to a place to store the dynamic linker's - * exit procedure pointer. + * exit procedure pointer and the third to a place to store the main + * program's object. * * The return value is the main program's entry point. */ func_ptr_type -_rtld(Elf32_Word *sp, func_ptr_type *exit_proc) +_rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) { - Elf32_Auxinfo *aux_info[AT_COUNT]; + Elf_Auxinfo *aux_info[AT_COUNT]; int i; int argc; char **argv; char **env; - Elf32_Auxinfo *aux; - Elf32_Auxinfo *auxp; + Elf_Auxinfo *aux; + Elf_Auxinfo *auxp; /* * On entry, the dynamic linker itself has not been relocated yet. @@ -196,7 +195,7 @@ _rtld(Elf32_Word *sp, func_ptr_type *exit_proc) env = (char **) sp; while (*sp++ != 0) /* Skip over environment, and NULL terminator */ ; - aux = (Elf32_Auxinfo *) sp; + aux = (Elf_Auxinfo *) sp; /* Digest the auxiliary vector. */ for (i = 0; i < AT_COUNT; i++) @@ -239,17 +238,17 @@ _rtld(Elf32_Word *sp, func_ptr_type *exit_proc) if (obj_main == NULL) die(); } else { /* Main program already loaded. */ - const Elf32_Phdr *phdr; + const Elf_Phdr *phdr; int phnum; caddr_t entry; dbg("processing main program's program header"); assert(aux_info[AT_PHDR] != NULL); - phdr = (const Elf32_Phdr *) aux_info[AT_PHDR]->a_un.a_ptr; + phdr = (const Elf_Phdr *) aux_info[AT_PHDR]->a_un.a_ptr; assert(aux_info[AT_PHNUM] != NULL); phnum = aux_info[AT_PHNUM]->a_un.a_val; assert(aux_info[AT_PHENT] != NULL); - assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf32_Phdr)); + assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf_Phdr)); assert(aux_info[AT_ENTRY] != NULL); entry = (caddr_t) aux_info[AT_ENTRY]->a_un.a_ptr; obj_main = digest_phdr(phdr, phnum, entry); @@ -294,24 +293,27 @@ _rtld(Elf32_Word *sp, func_ptr_type *exit_proc) r_debug_state(); /* say hello to gdb! */ /* Return the exit procedure and the program entry point. */ - *exit_proc = (func_ptr_type) rtld_exit; + *exit_proc = rtld_exit; + *objp = obj_main; return (func_ptr_type) obj_main->entry; } caddr_t -_rtld_bind(const Obj_Entry *obj, Elf32_Word reloff) +_rtld_bind(const Obj_Entry *obj, Elf_Word reloff) { - const Elf32_Rel *rel; - const Elf32_Sym *def; + const Elf_Rel *rel; + const Elf_Sym *def; const Obj_Entry *defobj; - Elf32_Addr *where; + Elf_Addr *where; caddr_t target; - rel = (const Elf32_Rel *) ((caddr_t) obj->pltrel + reloff); - assert(ELF32_R_TYPE(rel->r_info) == R_386_JMP_SLOT); + if (obj->pltrel) + rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff); + else + rel = (const Elf_Rel *) ((caddr_t) obj->pltrela + reloff); - where = (Elf32_Addr *) (obj->relocbase + rel->r_offset); - def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj, true); + where = (Elf_Addr *) (obj->relocbase + rel->r_offset); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true); if (def == NULL) die(); @@ -321,7 +323,7 @@ _rtld_bind(const Obj_Entry *obj, Elf32_Word reloff) defobj->strtab + def->st_name, basename(obj->path), target, basename(defobj->path)); - *where = (Elf32_Addr) target; + *where = (Elf_Addr) target; return target; } @@ -388,15 +390,16 @@ die(void) static void digest_dynamic(Obj_Entry *obj) { - const Elf32_Dyn *dynp; + const Elf_Dyn *dynp; Needed_Entry **needed_tail = &obj->needed; - const Elf32_Dyn *dyn_rpath = NULL; + const Elf_Dyn *dyn_rpath = NULL; + int plttype = DT_REL; for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; dynp++) { switch (dynp->d_tag) { case DT_REL: - obj->rel = (const Elf32_Rel *) (obj->relocbase + dynp->d_un.d_ptr); + obj->rel = (const Elf_Rel *) (obj->relocbase + dynp->d_un.d_ptr); break; case DT_RELSZ: @@ -404,11 +407,11 @@ digest_dynamic(Obj_Entry *obj) break; case DT_RELENT: - assert(dynp->d_un.d_val == sizeof(Elf32_Rel)); + assert(dynp->d_un.d_val == sizeof(Elf_Rel)); break; case DT_JMPREL: - obj->pltrel = (const Elf32_Rel *) + obj->pltrel = (const Elf_Rel *) (obj->relocbase + dynp->d_un.d_ptr); break; @@ -417,22 +420,29 @@ digest_dynamic(Obj_Entry *obj) break; case DT_RELA: + obj->rela = (const Elf_Rela *) (obj->relocbase + dynp->d_un.d_ptr); + break; + case DT_RELASZ: + obj->relasize = dynp->d_un.d_val; + break; + case DT_RELAENT: - assert(0); /* Should never appear for i386 */ + assert(dynp->d_un.d_val == sizeof(Elf_Rela)); break; case DT_PLTREL: - assert(dynp->d_un.d_val == DT_REL); /* For the i386 */ + plttype = dynp->d_un.d_val; + assert(dynp->d_un.d_val == DT_REL || plttype == DT_RELA); break; case DT_SYMTAB: - obj->symtab = (const Elf32_Sym *) + obj->symtab = (const Elf_Sym *) (obj->relocbase + dynp->d_un.d_ptr); break; case DT_SYMENT: - assert(dynp->d_un.d_val == sizeof(Elf32_Sym)); + assert(dynp->d_un.d_val == sizeof(Elf_Sym)); break; case DT_STRTAB: @@ -445,7 +455,7 @@ digest_dynamic(Obj_Entry *obj) case DT_HASH: { - const Elf32_Word *hashtab = (const Elf32_Word *) + const Elf_Addr *hashtab = (const Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr); obj->nbuckets = hashtab[0]; obj->nchains = hashtab[1]; @@ -468,7 +478,7 @@ digest_dynamic(Obj_Entry *obj) break; case DT_PLTGOT: - obj->got = (Elf32_Addr *) (obj->relocbase + dynp->d_un.d_ptr); + obj->got = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr); break; case DT_TEXTREL: @@ -502,11 +512,24 @@ digest_dynamic(Obj_Entry *obj) case DT_DEBUG: /* XXX - not implemented yet */ dbg("Filling in DT_DEBUG entry"); - ((Elf32_Dyn*)dynp)->d_un.d_ptr = (Elf32_Addr) &r_debug; + ((Elf_Dyn*)dynp)->d_un.d_ptr = (Elf_Addr) &r_debug; break; + + default: + xprintf("Ignored d_tag %d\n",dynp->d_tag); + break; } } + obj->traced = false; + + if (plttype == DT_RELA) { + obj->pltrela = (const Elf_Rela *) obj->pltrel; + obj->pltrel = NULL; + obj->pltrelasize = obj->pltrelsize; + obj->pltrelsize = 0; + } + if (dyn_rpath != NULL) obj->rpath = obj->strtab + dyn_rpath->d_un.d_val; } @@ -518,19 +541,19 @@ digest_dynamic(Obj_Entry *obj) * returns an Obj_Entry structure. */ static Obj_Entry * -digest_phdr(const Elf32_Phdr *phdr, int phnum, caddr_t entry) +digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry) { Obj_Entry *obj = CNEW(Obj_Entry); - const Elf32_Phdr *phlimit = phdr + phnum; - const Elf32_Phdr *ph; + const Elf_Phdr *phlimit = phdr + phnum; + const Elf_Phdr *ph; int nsegs = 0; for (ph = phdr; ph < phlimit; ph++) { switch (ph->p_type) { case PT_PHDR: - assert((const Elf32_Phdr *) ph->p_vaddr == phdr); - obj->phdr = (const Elf32_Phdr *) ph->p_vaddr; + assert((const Elf_Phdr *) ph->p_vaddr == phdr); + obj->phdr = (const Elf_Phdr *) ph->p_vaddr; obj->phsize = ph->p_memsz; break; @@ -550,7 +573,7 @@ digest_phdr(const Elf32_Phdr *phdr, int phnum, caddr_t entry) break; case PT_DYNAMIC: - obj->dynamic = (const Elf32_Dyn *) ph->p_vaddr; + obj->dynamic = (const Elf_Dyn *) ph->p_vaddr; break; } } @@ -577,61 +600,10 @@ dlcheck(void *handle) } /* - * Process the special R_386_COPY relocations in the main program. These - * copy data from a shared object into a region in the main program's BSS - * segment. - * - * Returns 0 on success, -1 on failure. - */ -static int -do_copy_relocations(Obj_Entry *dstobj) -{ - const Elf32_Rel *rellim; - const Elf32_Rel *rel; - - assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ - - rellim = (const Elf32_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); - for (rel = dstobj->rel; rel < rellim; rel++) { - if (ELF32_R_TYPE(rel->r_info) == R_386_COPY) { - void *dstaddr; - const Elf32_Sym *dstsym; - const char *name; - unsigned long hash; - size_t size; - const void *srcaddr; - const Elf32_Sym *srcsym; - Obj_Entry *srcobj; - - dstaddr = (void *) (dstobj->relocbase + rel->r_offset); - dstsym = dstobj->symtab + ELF32_R_SYM(rel->r_info); - name = dstobj->strtab + dstsym->st_name; - hash = elf_hash(name); - size = dstsym->st_size; - - for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) - if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL) - break; - - if (srcobj == NULL) { - _rtld_error("Undefined symbol \"%s\" referenced from COPY" - " relocation in %s", name, dstobj->path); - return -1; - } - - srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value); - memcpy(dstaddr, srcaddr, size); - } - } - - return 0; -} - -/* * Hash function for symbol table lookup. Don't even think about changing * this. It is specified by the System V ABI. */ -static unsigned long +unsigned long elf_hash(const char *name) { const unsigned char *p = (const unsigned char *) name; @@ -687,13 +659,13 @@ find_library(const char *name, const Obj_Entry *refobj) * no definition was found. Returns a pointer to the Obj_Entry of the * defining object via the reference parameter DEFOBJ_OUT. */ -static const Elf32_Sym * +const Elf_Sym * find_symdef(unsigned long symnum, const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt) { - const Elf32_Sym *ref; - const Elf32_Sym *strongdef; - const Elf32_Sym *weakdef; + const Elf_Sym *ref; + const Elf_Sym *strongdef; + const Elf_Sym *weakdef; const Obj_Entry *obj; const Obj_Entry *strongobj; const Obj_Entry *weakobj; @@ -705,7 +677,7 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj, hash = elf_hash(name); if (refobj->symbolic) { /* Look first in the referencing object */ - const Elf32_Sym *def = symlook_obj(name, hash, refobj, in_plt); + const Elf_Sym *def = symlook_obj(name, hash, refobj, in_plt); if (def != NULL) { *defobj_out = refobj; return def; @@ -723,9 +695,9 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj, strongobj = weakobj = NULL; for (obj = obj_list; obj != NULL; obj = obj->next) { if (obj != refobj || !refobj->symbolic) { - const Elf32_Sym *def = symlook_obj(name, hash, obj, in_plt); + const Elf_Sym *def = symlook_obj(name, hash, obj, in_plt); if (def != NULL) { - if (ELF32_ST_BIND(def->st_info) == STB_WEAK) { + if (ELF_ST_BIND(def->st_info) == STB_WEAK) { if (weakdef == NULL) { weakdef = def; weakobj = obj; @@ -747,9 +719,9 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj, * can be resolved from the dynamic linker. */ if (strongdef == NULL) { - const Elf32_Sym *def = symlook_obj(name, hash, &obj_rtld, in_plt); + const Elf_Sym *def = symlook_obj(name, hash, &obj_rtld, in_plt); if (def != NULL && is_exported(def)) { - if (ELF32_ST_BIND(def->st_info) == STB_WEAK) { + if (ELF_ST_BIND(def->st_info) == STB_WEAK) { if (weakdef == NULL) { weakdef = def; weakobj = &obj_rtld; @@ -789,9 +761,17 @@ init_rtld(caddr_t mapbase) obj_rtld.mapbase = mapbase; obj_rtld.relocbase = mapbase; obj_rtld.got = get_got_address(); - obj_rtld.dynamic = (const Elf32_Dyn *) (obj_rtld.mapbase + obj_rtld.got[0]); +#ifdef __alpha__ + obj_rtld.dynamic = (const Elf_Dyn *) &_DYNAMIC; +#else + obj_rtld.dynamic = (const Elf_Dyn *) (obj_rtld.mapbase + obj_rtld.got[0]); +#endif digest_dynamic(&obj_rtld); +#ifdef __alpha__ +/* XXX XXX XXX */ +obj_rtld.got = NULL; +#endif assert(obj_rtld.needed == NULL); assert(!obj_rtld.textrel); @@ -813,7 +793,7 @@ init_rtld(caddr_t mapbase) } static bool -is_exported(const Elf32_Sym *def) +is_exported(const Elf_Sym *def) { func_ptr_type value; const func_ptr_type *p; @@ -914,7 +894,7 @@ obj_from_addr(const void *addr) endhash = elf_hash(END_SYM); for (obj = obj_list; obj != NULL; obj = obj->next) { - const Elf32_Sym *endsym; + const Elf_Sym *endsym; if (addr < (void *) obj->mapbase) continue; @@ -938,9 +918,6 @@ relocate_objects(Obj_Entry *first, bool bind_now) Obj_Entry *obj; for (obj = first; obj != NULL; obj = obj->next) { - const Elf32_Rel *rellim; - const Elf32_Rel *rel; - if (obj->nbuckets == 0 || obj->nchains == 0 || obj->buckets == NULL || obj->symtab == NULL || obj->strtab == NULL) { _rtld_error("%s: Shared object has no run-time symbol table", @@ -959,89 +936,8 @@ relocate_objects(Obj_Entry *first, bool bind_now) } /* Process the non-PLT relocations. */ - rellim = (const Elf32_Rel *) ((caddr_t) obj->rel + obj->relsize); - for (rel = obj->rel; rel < rellim; rel++) { - Elf32_Addr *where = (Elf32_Addr *) (obj->relocbase + rel->r_offset); - - switch (ELF32_R_TYPE(rel->r_info)) { - - case R_386_NONE: - break; - - case R_386_32: - { - const Elf32_Sym *def; - const Obj_Entry *defobj; - - def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj, - false); - if (def == NULL) - return -1; - - *where += (Elf32_Addr) (defobj->relocbase + def->st_value); - } - break; - - case R_386_PC32: - /* - * I don't think the dynamic linker should ever see this - * type of relocation. But the binutils-2.6 tools sometimes - * generate it. - */ - { - const Elf32_Sym *def; - const Obj_Entry *defobj; - - def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj, - false); - if (def == NULL) - return -1; - - *where += - (Elf32_Addr) (defobj->relocbase + def->st_value) - - (Elf32_Addr) where; - } - break; - - case R_386_COPY: - /* - * These are deferred until all other relocations have - * been done. All we do here is make sure that the COPY - * relocation is not in a shared library. They are allowed - * only in executable files. - */ - if (!obj->mainprog) { - _rtld_error("%s: Unexpected R_386_COPY relocation" - " in shared library", obj->path); - return -1; - } - break; - - case R_386_GLOB_DAT: - { - const Elf32_Sym *def; - const Obj_Entry *defobj; - - def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj, - false); - if (def == NULL) - return -1; - - *where = (Elf32_Addr) (defobj->relocbase + def->st_value); - } - break; - - case R_386_RELATIVE: - *where += (Elf32_Addr) obj->relocbase; - break; - - default: - _rtld_error("%s: Unsupported relocation type %d" - " in non-PLT relocations\n", obj->path, - ELF32_R_TYPE(rel->r_info)); + if (reloc_non_plt(obj, &obj_rtld)) return -1; - } - } if (obj->textrel) { /* Re-protected the text segment. */ if (mprotect(obj->mapbase, obj->textsize, @@ -1053,30 +949,8 @@ relocate_objects(Obj_Entry *first, bool bind_now) } /* Process the PLT relocations. */ - rellim = (const Elf32_Rel *) ((caddr_t) obj->pltrel + obj->pltrelsize); - if (bind_now) { - /* Fully resolve procedure addresses now */ - for (rel = obj->pltrel; rel < rellim; rel++) { - Elf32_Addr *where = (Elf32_Addr *) - (obj->relocbase + rel->r_offset); - const Elf32_Sym *def; - const Obj_Entry *defobj; - - assert(ELF32_R_TYPE(rel->r_info) == R_386_JMP_SLOT); - - def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj, true); - if (def == NULL) - return -1; - - *where = (Elf32_Addr) (defobj->relocbase + def->st_value); - } - } else { /* Just relocate the GOT slots pointing into the PLT */ - for (rel = obj->pltrel; rel < rellim; rel++) { - Elf32_Addr *where = (Elf32_Addr *) - (obj->relocbase + rel->r_offset); - *where += (Elf32_Addr) obj->relocbase; - } - } + if (reloc_plt(obj, bind_now)) + return -1; /* * Set up the magic number and version in the Obj_Entry. These @@ -1088,8 +962,16 @@ relocate_objects(Obj_Entry *first, bool bind_now) /* Set the special GOT entries. */ if (obj->got) { - obj->got[1] = (Elf32_Addr) obj; - obj->got[2] = (Elf32_Addr) &_rtld_bind_start; +#ifdef __i386__ + obj->got[1] = (Elf_Addr) obj; + obj->got[2] = (Elf_Addr) &_rtld_bind_start; +#endif +#ifdef __alpha__ + /* This function will be called to perform the relocation. */ + obj->got[2] = (Elf_Addr) &_rtld_bind_start; + /* Identify this shared object */ + obj->got[3] = (Elf_Addr) obj; +#endif } } @@ -1239,7 +1121,7 @@ dlsym(void *handle, const char *name) { const Obj_Entry *obj; unsigned long hash; - const Elf32_Sym *def; + const Elf_Sym *def; hash = elf_hash(name); def = NULL; @@ -1341,14 +1223,14 @@ r_debug_state(void) * The symbol's hash value is passed in for efficiency reasons; that * eliminates many recomputations of the hash value. */ -static const Elf32_Sym * +const Elf_Sym * symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, bool in_plt) { unsigned long symnum = obj->buckets[hash % obj->nbuckets]; while (symnum != STN_UNDEF) { - const Elf32_Sym *symp; + const Elf_Sym *symp; const char *strp; assert(symnum < obj->nchains); @@ -1359,7 +1241,7 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, if (strcmp(name, strp) == 0) return symp->st_shndx != SHN_UNDEF || (!in_plt && symp->st_value != 0 && - ELF32_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL; + ELF_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL; symnum = obj->chains[symnum]; } diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 679a676..f1a9afd 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -22,7 +22,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: rtld.h,v 1.3 1998/08/21 03:29:40 jb Exp $ + * $Id: rtld.h,v 1.4 1998/09/02 02:51:12 jdp Exp $ */ #ifndef RTLD_H /* { */ @@ -88,15 +88,19 @@ typedef struct Struct_Obj_Entry { Elf_Addr *got; /* GOT table */ const Elf_Rel *rel; /* Relocation entries */ unsigned long relsize; /* Size in bytes of relocation info */ + const Elf_Rela *rela; /* Relocation entries with addend */ + unsigned long relasize; /* Size in bytes of addend relocation info */ const Elf_Rel *pltrel; /* PLT relocation entries */ unsigned long pltrelsize; /* Size in bytes of PLT relocation info */ + const Elf_Rela *pltrela; /* PLT relocation entries with addend */ + unsigned long pltrelasize; /* Size in bytes of PLT addend reloc info */ const Elf_Sym *symtab; /* Symbol table */ const char *strtab; /* String table */ unsigned long strsize; /* Size in bytes of string table */ - const Elf_Word *buckets; /* Hash table buckets array */ + const Elf_Addr *buckets; /* Hash table buckets array */ unsigned long nbuckets; /* Number of buckets */ - const Elf_Word *chains; /* Hash table chain array */ + const Elf_Addr *chains; /* Hash table chain array */ unsigned long nchains; /* Number of chains */ const char *rpath; /* Search path specified in object */ @@ -122,5 +126,18 @@ extern Obj_Entry *map_object(int); extern void *xcalloc(size_t); extern void *xmalloc(size_t); extern char *xstrdup(const char *); +extern Elf_Addr _GLOBAL_OFFSET_TABLE_[]; + +/* + * Function declarations. + */ +int do_copy_relocations(Obj_Entry *); +int reloc_non_plt(Obj_Entry *, Obj_Entry *); +int reloc_plt(Obj_Entry *, bool); +unsigned long elf_hash(const char *); +const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *, + const Obj_Entry **, bool); +const Elf_Sym *symlook_obj(const char *, unsigned long, + const Obj_Entry *, bool); #endif /* } */ |