rtld: Implement ELF filters (DT_FILTER and DT_AUXILIARY)
[dragonfly.git] / libexec / rtld-elf / i386 / reloc.c
index adf7774..5b0c68a 100644 (file)
@@ -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.
  *
- * $FreeBSD: src/libexec/rtld-elf/i386/reloc.c,v 1.22 2010/12/25 08:51:20 kib Exp $
+ * $FreeBSD$
  */
 
 /*
@@ -65,29 +65,34 @@ do_copy_relocations(Obj_Entry *dstobj)
 
     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;
-           unsigned long hash;
            size_t size;
            const void *srcaddr;
            const Elf_Sym *srcsym;
-           const Ver_Entry *ve;
-           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;
-           hash = elf_hash(name);
            size = dstsym->st_size;
-           ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
-
-           for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-               if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != 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;
+               }
+           }
 
            if (srcobj == NULL) {
                _rtld_error("Undefined symbol \"%s\" referenced from COPY"
@@ -95,7 +100,7 @@ do_copy_relocations(Obj_Entry *dstobj)
                return -1;
            }
 
-           srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
+           srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
            memcpy(dstaddr, srcaddr, size);
        }
     }
@@ -115,7 +120,7 @@ init_pltgot(Obj_Entry *obj)
 
 /* Process the non-PLT relocations. */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
        const Elf_Rel *rellim;
        const Elf_Rel *rel;
@@ -132,7 +137,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
        } else
            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);
 
@@ -147,7 +152,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
                    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;
 
@@ -166,7 +171,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
                    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;
 
@@ -196,7 +201,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
                    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;
 
@@ -214,7 +219,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
                    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;
 
@@ -274,7 +279,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
                    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;
 
@@ -288,7 +293,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
                    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;
 
@@ -317,42 +322,59 @@ reloc_plt(Obj_Entry *obj)
     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;
 
-       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
-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;
-    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, target;
        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;
-       target = (Elf_Addr)(defobj->relocbase + def->st_value);
-       reloc_jmpslot(where, target, defobj, obj, rel);
+       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;
 }
@@ -384,4 +406,3 @@ __tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti)
 {
     return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
 }
-