rtld: Implement ELF filters (DT_FILTER and DT_AUXILIARY)
[dragonfly.git] / libexec / rtld-elf / i386 / reloc.c
index b5ed9be..5b0c68a 100644 (file)
@@ -22,8 +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.
  *
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/i386/reloc.c,v 1.6.2.2 2002/06/16 20:02:09 dillon Exp $
- * $DragonFly: src/libexec/rtld-elf/i386/reloc.c,v 1.13 2005/05/11 19:47:09 dillon Exp $
+ * $FreeBSD$
  */
 
 /*
  */
 
 /*
@@ -66,27 +65,34 @@ do_copy_relocations(Obj_Entry *dstobj)
 
     assert(dstobj->mainprog);  /* COPY relocations are invalid elsewhere */
 
 
     assert(dstobj->mainprog);  /* COPY relocations are invalid elsewhere */
 
-    rellim = (const Elf_Rel *) ((c_caddr_t) dstobj->rel + dstobj->relsize);
+    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;
     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;
            size_t size;
            const void *srcaddr;
            const Elf_Sym *srcsym;
-           Obj_Entry *srcobj;
+           const Obj_Entry *srcobj, *defobj;
+           SymLook req;
+           int res;
 
            dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
            dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
            name = dstobj->strtab + dstsym->st_name;
 
            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;
            size = dstsym->st_size;
-
-           for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-               if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL)
+           symlook_init(&req, name);
+           req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
+
+           for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next) {
+               res = symlook_obj(&req, srcobj);
+               if (res == 0) {
+                   srcsym = req.sym_out;
+                   defobj = req.defobj_out;
                    break;
                    break;
+               }
+           }
 
            if (srcobj == NULL) {
                _rtld_error("Undefined symbol \"%s\" referenced from COPY"
 
            if (srcobj == NULL) {
                _rtld_error("Undefined symbol \"%s\" referenced from COPY"
@@ -94,7 +100,7 @@ do_copy_relocations(Obj_Entry *dstobj)
                return -1;
            }
 
                return -1;
            }
 
-           srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
+           srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
            memcpy(dstaddr, srcaddr, size);
        }
     }
            memcpy(dstaddr, srcaddr, size);
        }
     }
@@ -114,23 +120,24 @@ init_pltgot(Obj_Entry *obj)
 
 /* Process the non-PLT relocations. */
 int
 
 /* Process the non-PLT relocations. */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
        const Elf_Rel *rellim;
        const Elf_Rel *rel;
        SymCache *cache;
 {
        const Elf_Rel *rellim;
        const Elf_Rel *rel;
        SymCache *cache;
-       int bytes = obj->nchains * sizeof(SymCache);
        int r = -1;
 
        /*
         * The dynamic loader may be called from a thread, we have
         * limited amounts of stack available so we cannot use alloca().
         */
        int r = -1;
 
        /*
         * The dynamic loader may be called from a thread, we have
         * limited amounts of stack available so we cannot use alloca().
         */
-       cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
-       if (cache == MAP_FAILED)
+       if (obj != obj_rtld) {
+           cache = calloc(obj->nchains, sizeof(SymCache));
+           /* No need to check for NULL here */
+       } else
            cache = NULL;
 
            cache = NULL;
 
-       rellim = (const Elf_Rel *) ((c_caddr_t) obj->rel + obj->relsize);
+       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);
 
        for (rel = obj->rel;  rel < rellim;  rel++) {
            Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
 
@@ -145,7 +152,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-                     false, cache);
+                     false, cache, lockstate);
                    if (def == NULL)
                        goto done;
 
                    if (def == NULL)
                        goto done;
 
@@ -164,7 +171,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-                     false, cache);
+                     false, cache, lockstate);
                    if (def == NULL)
                        goto done;
 
                    if (def == NULL)
                        goto done;
 
@@ -194,7 +201,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-                     false, cache);
+                     false, cache, lockstate);
                    if (def == NULL)
                        goto done;
 
                    if (def == NULL)
                        goto done;
 
@@ -212,7 +219,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-                     false, cache);
+                     false, cache, lockstate);
                    if (def == NULL)
                        goto done;
 
                    if (def == NULL)
                        goto done;
 
@@ -272,7 +279,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-                     false, cache);
+                     false, cache, lockstate);
                    if (def == NULL)
                        goto done;
 
                    if (def == NULL)
                        goto done;
 
@@ -286,7 +293,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
                    const Obj_Entry *defobj;
 
                    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-                     false, cache);
+                     false, cache, lockstate);
                    if (def == NULL)
                        goto done;
 
                    if (def == NULL)
                        goto done;
 
@@ -303,8 +310,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
        }
        r = 0;
 done:
        }
        r = 0;
 done:
-       if (cache)
-           munmap(cache, bytes);
+       if (cache != NULL)
+           free(cache);
        return(r);
 }
 
        return(r);
 }
 
@@ -315,41 +322,59 @@ reloc_plt(Obj_Entry *obj)
     const Elf_Rel *rellim;
     const Elf_Rel *rel;
 
     const Elf_Rel *rellim;
     const Elf_Rel *rel;
 
-    rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
+    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
     for (rel = obj->pltrel;  rel < rellim;  rel++) {
        Elf_Addr *where;
 
     for (rel = obj->pltrel;  rel < rellim;  rel++) {
        Elf_Addr *where;
 
-       assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
-
-       /* Relocate the GOT slot pointing into the PLT. */
-       where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
-       *where += (Elf_Addr)obj->relocbase;
+       switch (ELF_R_TYPE(rel->r_info)) {
+       case R_386_JMP_SLOT:
+         /* Relocate the GOT slot pointing into the PLT. */
+         where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+         *where += (Elf_Addr)obj->relocbase;
+         break;
+
+       default:
+         _rtld_error("Unknown relocation type %x in PLT",
+           ELF_R_TYPE(rel->r_info));
+         return (-1);
+       }
     }
     return 0;
 }
 
 /* Relocate the jump slots in an object. */
 int
     }
     return 0;
 }
 
 /* Relocate the jump slots in an object. */
 int
-reloc_jmpslots(Obj_Entry *obj)
+reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
 {
     const Elf_Rel *rellim;
     const Elf_Rel *rel;
 
     if (obj->jmpslots_done)
        return 0;
 {
     const Elf_Rel *rellim;
     const Elf_Rel *rel;
 
     if (obj->jmpslots_done)
        return 0;
-    rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
+    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
     for (rel = obj->pltrel;  rel < rellim;  rel++) {
     for (rel = obj->pltrel;  rel < rellim;  rel++) {
-       Elf_Addr *where;
+       Elf_Addr *where, target;
        const Elf_Sym *def;
        const Obj_Entry *defobj;
 
        const Elf_Sym *def;
        const Obj_Entry *defobj;
 
-       assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
-       where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
-       def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL);
-       if (def == NULL)
-           return -1;
-       reloc_jmpslot(where, (Elf_Addr)(defobj->relocbase + def->st_value));
+       switch (ELF_R_TYPE(rel->r_info)) {
+       case R_386_JMP_SLOT:
+         where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+         def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL,
+             lockstate);
+         if (def == NULL)
+             return (-1);
+         target = (Elf_Addr)(defobj->relocbase + def->st_value);
+         reloc_jmpslot(where, target, defobj, obj, rel);
+         break;
+
+       default:
+         _rtld_error("Unknown relocation type %x in PLT",
+           ELF_R_TYPE(rel->r_info));
+         return (-1);
+       }
     }
     }
+
     obj->jmpslots_done = true;
     return 0;
 }
     obj->jmpslots_done = true;
     return 0;
 }
@@ -362,7 +387,7 @@ ___tls_get_addr(tls_index *ti)
     struct tls_tcb *tcb;
 
     tcb = tls_get_tcb();
     struct tls_tcb *tcb;
 
     tcb = tls_get_tcb();
-    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+    return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
 }
 
 /* Sun ABI */
 }
 
 /* Sun ABI */
@@ -372,13 +397,12 @@ __tls_get_addr(tls_index *ti)
     struct tls_tcb *tcb;
 
     tcb = tls_get_tcb();
     struct tls_tcb *tcb;
 
     tcb = tls_get_tcb();
-    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+    return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
 }
 
 /* Sun ABI */
 void *
 __tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti)
 {
 }
 
 /* Sun ABI */
 void *
 __tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti)
 {
-    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+    return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
 }
 }
-