Add support for R_ARM_FUNCDESC_VALUE and implement _dl_linux_resolver
for FDPIC on ARM.

        * ldso/ldso/arm/elfinterp.c (_dl_linux_resolver): Support __FDPIC__.
        (_dl_do_lazy_reloc): Likewise.
        * ldso/ldso/arm/resolve.S (_dl_linux_resolve): Likewise.

Signed-off-by: Mickaël Guêné <mickael.gu...@st.com>
Signed-off-by: Christophe Lyon <christophe.l...@st.com>

diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c
index 1435c2c..3bcd675 100644
--- a/ldso/ldso/arm/elfinterp.c
+++ b/ldso/ldso/arm/elfinterp.c
@@ -34,13 +34,69 @@
 
 extern int _dl_linux_resolve(void);
 
-unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
-{
 #if __FDPIC__
-  /* FIXME: implement.  */
-  while(1) ;
-  return 0;
+unsigned long _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_offet)
+{
+       ELF_RELOC *this_reloc;
+       char *strtab;
+       ElfW(Sym) *symtab;
+       int symtab_index;
+       char *rel_addr;
+       char *new_addr;
+       struct funcdesc_value funcval;
+       struct funcdesc_value volatile *got_entry;
+       char *symname;
+       struct symbol_ref sym_ref;
+
+       rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
+
+       this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_offet);
+       symtab_index = ELF_R_SYM(this_reloc->r_info);
+
+       symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
+       strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
+       sym_ref.sym = &symtab[symtab_index];
+       sym_ref.tpnt = NULL;
+       symname= strtab + symtab[symtab_index].st_name;
+
+       /* Address of GOT entry fix up */
+       got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, 
this_reloc->r_offset);
+
+       /* Get the address to be used to fill in the GOT entry.  */
+       new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, 
NULL, 0, &sym_ref);
+       if (!new_addr) {
+               new_addr = _dl_find_hash(symname, NULL, NULL, 0, &sym_ref);
+               if (!new_addr) {
+                       _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", 
_dl_progname, symname);
+                       _dl_exit(1);
+               }
+       }
+
+       funcval.entry_point = new_addr;
+       funcval.got_value = sym_ref.tpnt->loadaddr.got_value;
+
+#if defined (__SUPPORT_LD_DEBUG__)
+       if (_dl_debug_bindings) {
+               _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
+               if (_dl_debug_detail)
+                       _dl_dprintf(_dl_debug_file,
+                                   "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
+                                   got_entry->entry_point, 
got_entry->got_value,
+                                   funcval.entry_point, funcval.got_value,
+                                   got_entry);
+       }
+       if (1 || !_dl_debug_nofixups) {
+               *got_entry = funcval;
+       }
+#else
+       *got_entry = funcval;
+#endif
+
+       return got_entry;
+}
 #else
+unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
+{
        ELF_RELOC *this_reloc;
        char *strtab;
        char *symname;
@@ -93,8 +149,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, 
int reloc_entry)
 #endif
 
        return new_addr;
-#endif
 }
+#endif
 
 static int
 _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
@@ -346,7 +402,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
        int reloc_type;
        unsigned long *reloc_addr;
 
-       reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) 
rpnt->r_offset);
+       reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, 
rpnt->r_offset);
        reloc_type = ELF_R_TYPE(rpnt->r_info);
 
 #if defined (__SUPPORT_LD_DEBUG__)
@@ -356,8 +412,17 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
                switch (reloc_type) {
                        case R_ARM_NONE:
                                break;
+
                        case R_ARM_JUMP_SLOT:
-                               *reloc_addr += (unsigned long) tpnt->loadaddr;
+                               *reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, 
*reloc_addr);
+                               break;
+                       case R_ARM_FUNCDESC_VALUE:
+                               {
+                                       struct funcdesc_value *dst = (struct 
funcdesc_value *) reloc_addr;
+
+                                       dst->entry_point = 
DL_RELOC_ADDR(tpnt->loadaddr, dst->entry_point);
+                                       dst->got_value = 
tpnt->loadaddr.got_value;
+                               }
                                break;
                        default:
                                return -1; /*call _dl_exit(1) */
diff --git a/ldso/ldso/arm/resolve.S b/ldso/ldso/arm/resolve.S
index 2a51643..039a6b7 100644
--- a/ldso/ldso/arm/resolve.S
+++ b/ldso/ldso/arm/resolve.S
@@ -107,6 +107,27 @@
  .type _dl_linux_resolve,%function
  .align 4;
 
+#if __FDPIC__
+/*
+ *    _dl_linux_resolve() FDPIC version receives the following parameters from
+ *    lazy PLT entry:
+ *    R12: GOT address for the resolver GOT
+ *    SP[0]: funcdesc_value_reloc_offset(foo)
+ *    R9: GOT address for the caller GOT
+ *    _dl_linux_resolver() will return a function descriptor address in R0.
+ */
+_dl_linux_resolve:
+       push  {r0, r1, r2, r3, r14}
+       ldr   r0, [r9, #8]
+       ldr   r1, [sp, #20]
+       mov   r9, r12
+       blx   _dl_linux_resolver
+       ldr   r9, [r0, #4]
+       ldr   r12, [r0]
+       pop   {r0, r1, r2, r3, r14}
+       add   sp, sp, #4
+       bx    r12
+#else
 _dl_linux_resolve:
          @ _dl_linux_resolver is a standard subroutine call, therefore it
          @ preserves everything except r0-r3 (a1-a4), ip and lr.  This
@@ -129,6 +150,7 @@ _dl_linux_resolve:
         ldmia sp!, {r0, r1, r2, r3, r4, lr}
 
         BX(ip)
+#endif /* __FDPIC__ */
 #else
        @ In the thumb case _dl_linux_resolver is thumb.  If a bl is used
        @ from arm code the linker will insert a stub call which, with
-- 
2.6.3

_______________________________________________
devel mailing list
devel@uclibc-ng.org
https://mailman.uclibc-ng.org/cgi-bin/mailman/listinfo/devel

Reply via email to