summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Lyon <christophe.lyon@st.com>2013-03-28 09:46:55 (GMT)
committerWaldemar Brodkorb <wbrodkorb@conet.de>2018-08-10 14:02:45 (GMT)
commit6618d5aa2feedded6358ba9c3d50cb8ee08fbd20 (patch)
treedd693c70e275a2b435b097900688db59bb830381
parent448a986954f65cc8c41f227bdf171d8e0d0b4c7d (diff)
rtld: Add lazy binding support
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.guene@st.com> Signed-off-by: Christophe Lyon <christophe.lyon@st.com>
-rw-r--r--ldso/ldso/arm/elfinterp.c83
-rw-r--r--ldso/ldso/arm/resolve.S22
2 files changed, 97 insertions, 8 deletions
diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c
index 402ba96..1d79d92 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,
@@ -348,7 +404,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__)
@@ -358,9 +414,20 @@ _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;
+#ifdef __FDPIC__
+ 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;
+#endif
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