Re: [uclibc-ng-devel] [PATCH 11/32] [ARM][FDPIC] rtld: Add lazy binding support

2018-08-06 Thread Christophe Lyon

On 04/07/2018 17:55, Christophe Lyon wrote:

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


Here is v2 of this patch.

>From 060a6ac2e81f9aa739d2eaf31b151f9e7e7d468f Mon Sep 17 00:00:00 2001
From: Christophe Lyon 
Date: Thu, 28 Mar 2013 10:46:55 +0100
Subject: [PATCH 11/32] [ARM][FDPIC] rtld: Add lazy binding support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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é 
Signed-off-by: Christophe Lyon 

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_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, _ref);
+	if (!new_addr) {
+		new_addr = _dl_find_hash(symname, NULL, NULL, 0, _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   

[uclibc-ng-devel] [PATCH 11/32] [ARM][FDPIC] rtld: Add lazy binding support

2018-07-04 Thread Christophe Lyon
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é 
Signed-off-by: Christophe Lyon 

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_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, _ref);
+   if (!new_addr) {
+   new_addr = _dl_find_hash(symname, NULL, NULL, 0, _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