public inbox for libc-ports@sourceware.org
 help / color / mirror / Atom feed
* [RFC][PATCH] MIPS ifunc for glibc
@ 2013-08-17  0:31 Jack Carter
  2013-08-18 20:39 ` Joseph S. Myers
  0 siblings, 1 reply; 4+ messages in thread
From: Jack Carter @ 2013-08-17  0:31 UTC (permalink / raw)
  To: libc-ports


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

Note: This patch is for initial code review and has no test cases included.
They will be forth coming with submission for commit.

This is targeting o32. Patches for 64 bit, n32, MicroMips, Mips16,
and possibly vxworks will follow this patch. I have also not
yet implemented ifunc with local, hidden, or protected
symbol status.

Relocations using R_MIPS_IRELATIVE or referencting a symbol of type
STT_GNU_IFUNC have their affective address produced by executing the
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.

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

./ChangeLog

2013-08-16  Jack Carter  <jack.carter@imgtec.com>

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

ports/ChangeLog

2013-08-16  Jack Carter  <jack.carter@imgtec.com>

	* 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 f372271..78c347b 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1625,8 +1625,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..10acca8
--- /dev/null
+++ b/ports/sysdeps/mips/dl-irel.h
@@ -0,0 +1,62 @@
+/* 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%x), return(0x%x)\n",
+				addr,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 Elf32_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 dae938f..9293eb3 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 */
@@ -190,6 +191,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)					\
@@ -437,7 +440,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;
@@ -642,6 +646,21 @@ elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info,
 	break;
       }
 
+    case R_MIPS_IRELATIVE:
+      {
+	ElfW(Addr) value;
+
+	/* The address for the got entry storing the address for the */
+	/* ifunc routine is in this relocation. To get the address of */
+	/* the function to use on this machine the ifunc routine is run */
+	/* and its return value is the address which is then put back */
+	/* into the got entry. */
+	value = map->l_addr + *addr_field;
+	value = ((ElfW(Addr) (*) (void)) value) ();
+	*addr_field = value;
+	break;
+      }
+
 #if _MIPS_SIM == _ABI64
     case R_MIPS_64:
       /* For full compliance with the ELF64 ABI, one must precede the
@@ -671,7 +690,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
@@ -712,7 +732,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
@@ -739,8 +759,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 = ((ElfW(Addr) (*) (void)) value) ();			  \
+	}								  \
+      ref ? value : 0;							  \
     })
 
   if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
@@ -810,6 +837,13 @@ 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)
+	{
+	  ElfW(Addr) value;
+	  value = map->l_addr + *got;
+	  value = ((ElfW(Addr) (*) (void)) value) ();
+	  *got = value;
+	}
       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..661dfc4 100644
--- a/ports/sysdeps/mips/dl-trampoline.c
+++ b/ports/sysdeps/mips/dl-trampoline.c
@@ -193,6 +193,9 @@ __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

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-08-20 14:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-17  0:31 [RFC][PATCH] MIPS ifunc for glibc Jack Carter
2013-08-18 20:39 ` Joseph S. Myers
2013-08-20  0:38   ` Jack Carter
2013-08-20 14:03     ` Joseph S. Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).