This is the mail archive of the libc-ports@sources.redhat.com mailing list for the libc-ports project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] 2nd round of Mips ifunc support


Attached is the second pass for Mips ifunc support in glibc.

There is an abi attached as well.

Jack

Attachment: ifunc_abi.txt
Description: ifunc_abi.txt

This is the initial MIPS ifunc patch for glibc. This patch should be
applied in conjunction with the binutils patch.

This is targeting o32, n32 and 64 bit. Patches for MicroMips, Mips16,
and possibly vxworks will follow this patch. 

Relocations using R_MIPS_IRELATIVE or referencing a symbol of type
STT_GNU_IFUNC have their affective address produced by executing the resolver
function pointed by either the R_MIPS_IRELATIVE target or the STT_GNU_IFUNC
target. The resultant address is the final function effective address that 
will be used for the duration of the program execution.

There is an attached ABI that describes the runtime fixup in more detail.

***************************************

./ChangeLog
	* elf/elf.h:
	Define for R_MIPS_IRELATIVE and bump R_MIPS_NUM up to 129.

ports/ChangeLog
	* sysdeps/mips/dl-irel.h: New file.
	(elf_ifunc_invoke): Do the indirect reference.
	(elf_irel): Call elf_ifunc_invoke() for acceptable relocations.
	* sysdeps/mips/dl-machine.h: 
	Include new dl-irel.h.
	(ELF_MACHINE_BEFORE_RTLD_RELOC): Add check for STT_GNU_IFUNC.
	(elf_machine_reloc): Add skip_ifunc to parameter.
	Add case for R_MIPS_IRELATIVE.
	(elf_machine_rel): Add skip_ifunc to call to elf_machine_reloc().
	(elf_machine_rela):Add skip_ifunc to call to elf_machine_reloc().
	(RESOLVE_GOTSYM): Add check for STT_GNU_IFUNC.
	(elf_machine_got_rel): Add check for STT_GNU_IFUNC.
	* sysdeps/mips/dl-trampoline.c: 
	(__dl_runtime_resolve): Add check for STT_GNU_IFUNC.
diff --git a/elf/elf.h b/elf/elf.h
index a05ea3b..b3a89db 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1626,8 +1626,9 @@ typedef struct
 #define R_MIPS_GLOB_DAT		51
 #define R_MIPS_COPY		126
 #define R_MIPS_JUMP_SLOT        127
+#define R_MIPS_IRELATIVE        128
 /* Keep this the last entry.  */
-#define R_MIPS_NUM		128
+#define R_MIPS_NUM		129
 
 /* Legal values for p_type field of Elf32_Phdr.  */
 
diff --git a/ports/sysdeps/mips/dl-irel.h b/ports/sysdeps/mips/dl-irel.h
new file mode 100644
index 0000000..1891de0
--- /dev/null
+++ b/ports/sysdeps/mips/dl-irel.h
@@ -0,0 +1,63 @@
+/* Machine-dependent ELF indirect relocation inline functions.
+   MIPS version.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_IREL_H
+#define _DL_IREL_H
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sgidefs.h>
+#include <link.h>
+#include <elf.h>
+#include <ldsodefs.h>
+
+#define ELF_MACHINE_IREL	1
+
+static inline ElfW(Addr)
+__attribute ((always_inline))
+elf_ifunc_invoke (ElfW(Addr) addr)
+{
+  /* Print some debugging info if wanted.  */
+  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS, 0))
+      {
+	ElfW(Addr) t_addr =
+	    ((ElfW(Addr) (*) (unsigned long int)) (addr)) (GLRO(dl_hwcap));
+	GLRO(dl_debug_printf) ("In elf_ifunc_invoke(0x%lx), return(0x%lx)\n",
+				(unsigned long int)addr,
+				(unsigned long int)t_addr);
+      }
+
+  return ((ElfW(Addr) (*) (unsigned long int)) (addr)) (GLRO(dl_hwcap));
+}
+
+/* Allow either R_MIPS_RELATIVE or the nop R_MIPS_NONE */
+static inline void
+__attribute ((always_inline))
+elf_irel (const ElfW(Rel) *reloc)
+{
+  ElfW(Addr) *const reloc_addr = (void *) reloc->r_offset;
+  const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
+
+  if (__builtin_expect (r_type == R_MIPS_IRELATIVE, 1))
+    *reloc_addr = elf_ifunc_invoke (*reloc_addr);
+  else if (r_type)
+     __libc_fatal ("unexpected reloc type in static binary\n");
+}
+
+#endif /* dl-irel.h */
diff --git a/ports/sysdeps/mips/dl-machine.h b/ports/sysdeps/mips/dl-machine.h
index 722c8a0..671aa1f 100644
--- a/ports/sysdeps/mips/dl-machine.h
+++ b/ports/sysdeps/mips/dl-machine.h
@@ -32,6 +32,7 @@
 #include <sgidefs.h>
 #include <sys/asm.h>
 #include <dl-tls.h>
+#include <dl-irel.h>
 
 /* The offset of gp from GOT might be system-dependent.  It's set by
    ld.  The same value is also */
@@ -204,6 +205,8 @@ do {									\
       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC			\
 	       && *got != sym->st_value)				\
 	*got += map->l_addr;						\
+      else if (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)		\
+	*got = elf_ifunc_invoke(sym->st_value);				\
       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)		\
 	{								\
 	  if (sym->st_other == 0)					\
@@ -451,7 +454,8 @@ auto inline void
 __attribute__ ((always_inline))
 elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info,
 		   const ElfW(Sym) *sym, const struct r_found_version *version,
-		   void *reloc_addr, ElfW(Addr) r_addend, int inplace_p)
+		   void *reloc_addr, ElfW(Addr) r_addend, int inplace_p,
+		   int skip_ifunc)
 {
   const unsigned long int r_type = ELFW(R_TYPE) (r_info);
   ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr;
@@ -656,6 +660,14 @@ elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info,
 	break;
       }
 
+    case R_MIPS_IRELATIVE:
+      /* The resolver routine is the symbol referenced by this relocation.
+	 To get the address of the function to use at runtime, the resolver
+	 routine is called and its return value is the address of the target
+	 functon which is final relocation value. */
+      *addr_field = elf_ifunc_invoke (map->l_addr + *addr_field);
+      break;
+
 #if _MIPS_SIM == _ABI64
     case R_MIPS_64:
       /* For full compliance with the ELF64 ABI, one must precede the
@@ -685,7 +697,8 @@ elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
 		 const ElfW(Sym) *sym, const struct r_found_version *version,
 		 void *const reloc_addr, int skip_ifunc)
 {
-  elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr, 0, 1);
+  elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr, 0, 1, 
+		     skip_ifunc);
 }
 
 auto inline void
@@ -726,7 +739,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
 		  void *const reloc_addr, int skip_ifunc)
 {
   elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr,
-		     reloc->r_addend, 0);
+		     reloc->r_addend, 0, skip_ifunc);
 }
 
 auto inline void
@@ -753,8 +766,15 @@ elf_machine_got_rel (struct link_map *map, int lazy)
       const struct r_found_version *version __attribute__ ((unused))	  \
 	= vernum ? &map->l_versions[vernum[sym_index] & 0x7fff] : NULL;	  \
       struct link_map *sym_map;						  \
+      ElfW(Addr) value;							  \
       sym_map = RESOLVE_MAP (&ref, version, reloc);			  \
-      ref ? sym_map->l_addr + ref->st_value : 0;			  \
+      if (ref)								  \
+	{								  \
+	  value = sym_map->l_addr + ref->st_value;			  \
+	  if (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC)		  \
+	    value = elf_ifunc_invoke (value);				  \
+	}								  \
+      ref ? value : 0;							  \
     })
 
   if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
@@ -824,6 +844,8 @@ elf_machine_got_rel (struct link_map *map, int lazy)
 	  if (sym->st_other == 0)
 	    *got += map->l_addr;
 	}
+      else if (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
+	*got = elf_ifunc_invoke (map->l_addr + *got);
       else
 	*got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
 
diff --git a/ports/sysdeps/mips/dl-trampoline.c b/ports/sysdeps/mips/dl-trampoline.c
index 605e44e..0a510f3 100644
--- a/ports/sysdeps/mips/dl-trampoline.c
+++ b/ports/sysdeps/mips/dl-trampoline.c
@@ -193,6 +193,10 @@ __dl_runtime_resolve (ElfW(Word) sym_index,
       /* Currently value contains the base load address of the object
 	 that defines sym.  Now add in the symbol offset.  */
       value = (sym ? sym_map->l_addr + sym->st_value : 0);
+      if (sym != NULL
+          && __builtin_expect (ELFW(ST_TYPE) (sym->st_info)
+              == STT_GNU_IFUNC, 0))
+        value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
     }
   else
     /* We already found the symbol.  The module (and therefore its load

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]