This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc 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: Finish STT_GNU_IFUNC support


Hi,

This patch finishes STT_GNU_IFUNC support. It works with STT_GNU_IFUNC
symbols in shared library, dynamic executable and static executable.

You need the Linux binutils 2.19.51.0.6 or above at

http://www.kernel.org/pub/linux/devel/binutils/

to use it.


H.J.
---
2009-05-29  H.J. Lu  <hongjiu.lu@intel.com>

	* csu/elf-init.c: Include <link.h> and <dl-irel.h> if
	LIBC_NONSHARED is not defined.
	(__rela_iplt_start): New.
	(__rela_iplt_end): Likewise.
	(__rel_iplt_start): Likewise.
	(__rel_iplt_end): Likewise.
	(__libc_csu_init): Process __rela_iplt_start and
	__rel_iplt_start.

	* elf/elf.h (R_386_IRELATIVE): New.
	(R_X86_64_IRELATIVE): Likewise.
	(R_386_NUM): Updated.
	(R_X86_64_NUM): Likewise.

	* include/libc-symbols.h (libc_ifunc_hidden_def1): New.
	(libc_ifunc_hidden_def): Likewise.

	* sysdeps/generic/dl-irel.h: New.
	* sysdeps/i386/dl-irel.h: Likewise.
	* sysdeps/x86_64/dl-irel.h: Likewise.

	* sysdeps/i386/dl-machine.h (elf_machine_rel): Handle
	R_386_IRELATIVE.
	(elf_machine_rela): Check SHN_UNDEF for STT_GNU_IFUNC symbol.
	Handle R_386_IRELATIVE.
	(elf_machine_lazy_rel): Handle R_386_IRELATIVE.
	(elf_machine_lazy_rela): Likewise.

	* sysdeps/x86_64/dl-machine.h (elf_machine_rela): Handle
	R_X86_64_IRELATIVE.
	(elf_machine_lazy_rel): Handle R_X86_64_IRELATIVE.

diff --git a/csu/elf-init.c b/csu/elf-init.c
index 27eae15..a0f2bc9 100644
--- a/csu/elf-init.c
+++ b/csu/elf-init.c
@@ -36,6 +36,20 @@
 
 #include <stddef.h>
 
+#ifndef LIBC_NONSHARED
+#include <link.h>
+#include <dl-irel.h>
+
+#ifdef ELF_MACHINE_IRELA
+extern const ElfW(Rela) __rela_iplt_start [];
+extern const ElfW(Rela) __rela_iplt_end [];
+#endif
+
+#ifdef ELF_MACHINE_IREL
+extern const ElfW(Rel) __rel_iplt_start [];
+extern const ElfW(Rel) __rel_iplt_end [];
+#endif
+#endif	/* LIBC_NONSHARED */
 
 /* These magic symbols are provided by the linker.  */
 extern void (*__preinit_array_start []) (int, char **, char **)
@@ -67,6 +81,24 @@ __libc_csu_init (int argc, char **argv, char **envp)
      the dynamic linker (before initializing any shared object.  */
 
 #ifndef LIBC_NONSHARED
+#ifdef ELF_MACHINE_IRELA
+  {
+    const size_t size = __rela_iplt_end - __rela_iplt_start;
+    size_t i;
+    for (i = 0; i < size; i++)
+      elf_irela (&__rela_iplt_start [i]);
+  }
+#endif
+
+#ifdef ELF_MACHINE_IREL
+  {
+    const size_t size = __rel_iplt_end - __rel_iplt_start;
+    size_t i;
+    for (i = 0; i < size; i++)
+      elf_irel (&__rel_iplt_start [i]);
+  }
+#endif
+
   /* For static executables, preinit happens rights before init.  */
   {
     const size_t size = __preinit_array_end - __preinit_array_start;
diff --git a/elf/elf.h b/elf/elf.h
index 062ef00..8fdf74b 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1177,8 +1177,9 @@ typedef struct
 					   pointer to code and to
 					   argument, returning the TLS
 					   offset for the symbol.  */
+#define R_386_IRELATIVE	   42		/* Adjust indirectly by program base */
 /* Keep this the last entry.  */
-#define R_386_NUM	   42
+#define R_386_NUM	   43
 
 /* SUN SPARC specific definitions.  */
 
@@ -2625,8 +2626,9 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_X86_64_TLSDESC_CALL   35	/* Marker for call through TLS
 					   descriptor.  */
 #define R_X86_64_TLSDESC        36	/* TLS descriptor.  */
+#define R_X86_64_IRELATIVE	37	/* Adjust indirectly by program base */
 
-#define R_X86_64_NUM		37
+#define R_X86_64_NUM		38
 
 
 /* AM33 relocations.  */
diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index d53bcb9..68da77c 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -845,4 +845,21 @@ for linking")
   }									\
   __asm__ (".type " #name ", %gnu_indirect_function");
 
+#ifdef HAVE_ASM_SET_DIRECTIVE
+# define libc_ifunc_hidden_def1(local, name)				\
+    __asm__ (declare_symbol_alias_1_stringify (ASM_GLOBAL_DIRECTIVE)	\
+	     " " #local "\n\t"						\
+	     ".hidden " #local "\n\t"					\
+	     ".set " #local ", " #name);
+#else
+# define libc_ifunc_hidden_def1(local, name)				\
+    __asm__ (declare_symbol_alias_1_stringify (ASM_GLOBAL_DIRECTIVE)	\
+	     " " #local "\n\t"						\
+	     ".hidden " #local "\n\t"					\
+	     #local " = " #name);
+#endif
+
+#define libc_ifunc_hidden_def(name) \
+  libc_ifunc_hidden_def1 (__GI_##name, name)
+
 #endif /* libc-symbols.h */
diff --git a/sysdeps/generic/dl-irel.h b/sysdeps/generic/dl-irel.h
new file mode 100644
index 0000000..c7d8adb
--- /dev/null
+++ b/sysdeps/generic/dl-irel.h
@@ -0,0 +1,23 @@
+/* Machine-dependent ELF indirect relocation inline functions.
+   Copyright (C) 2009 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef dl_irel_h
+#define dl_irel_h
+
+#endif /* !dl_irel_h */
diff --git a/sysdeps/i386/dl-irel.h b/sysdeps/i386/dl-irel.h
new file mode 100644
index 0000000..3ad7fb0
--- /dev/null
+++ b/sysdeps/i386/dl-irel.h
@@ -0,0 +1,44 @@
+/* Machine-dependent ELF indirect relocation inline functions.
+   i386 version.
+   Copyright (C) 2009 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef dl_irel_h
+#define dl_irel_h
+
+#include <unistd.h>
+
+#define ELF_MACHINE_IREL	1
+
+static inline void
+__attribute ((always_inline))
+elf_irel (const Elf32_Rel *reloc)
+{
+  Elf32_Addr *const reloc_addr = (void *) reloc->r_offset;
+  const unsigned long int r_type = ELF32_R_TYPE (reloc->r_info);
+
+  if (__builtin_expect (r_type == R_386_IRELATIVE, 1))
+    {
+      Elf64_Addr value = ((Elf32_Addr (*) (void)) (*reloc_addr)) ();
+      *reloc_addr = value;
+    }
+  else
+    _exit (-1);
+}
+
+#endif /* !dl_irel_h */
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 0e15878..efa929e 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -345,6 +345,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
       Elf32_Addr value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
 
       if (sym != NULL
+	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
 	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
 			       0))
 	value = ((Elf32_Addr (*) (void)) value) ();
@@ -471,6 +472,11 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 	  memcpy (reloc_addr_arg, (void *) value,
 		  MIN (sym->st_size, refsym->st_size));
 	  break;
+	case R_386_IRELATIVE:
+	  value = map->l_addr + *reloc_addr;
+	  value = ((Elf32_Addr (*) (void)) value) ();
+	  *reloc_addr = value;
+	  break;
 	default:
 	  _dl_reloc_bad_type (map, r_type, 0);
 	  break;
@@ -500,6 +506,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
       Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
 
       if (sym != NULL
+	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
 	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
 			       0))
 	value = ((Elf32_Addr (*) (void)) value) ();
@@ -609,6 +616,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 		  MIN (sym->st_size, refsym->st_size));
 	  break;
 #  endif /* !RESOLVE_CONFLICT_FIND_MAP */
+	case R_386_IRELATIVE:
+	  value = map->l_addr + reloc->r_addend;
+	  value = ((Elf32_Addr (*) (void)) value) ();
+	  *reloc_addr = value;
+	  break;
 	default:
 	  /* We add these checks in the version to relocate ld.so only
 	     if we are still debugging.  */
@@ -703,6 +715,12 @@ elf_machine_lazy_rel (struct link_map *map,
 # endif
 	}
     }
+  else if (__builtin_expect (r_type == R_386_IRELATIVE, 0))
+    {
+      Elf32_Addr value = map->l_addr + *reloc_addr;
+      value = ((Elf32_Addr (*) (void)) value) ();
+      *reloc_addr = value;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }
@@ -726,6 +744,12 @@ elf_machine_lazy_rela (struct link_map *map,
       td->arg = (void*)reloc;
       td->entry = _dl_tlsdesc_resolve_rela;
     }
+  else if (__builtin_expect (r_type == R_386_IRELATIVE, 0))
+    {
+      Elf32_Addr value = map->l_addr + reloc->r_addend;
+      value = ((Elf32_Addr (*) (void)) value) ();
+      *reloc_addr = value;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }
diff --git a/sysdeps/x86_64/dl-irel.h b/sysdeps/x86_64/dl-irel.h
new file mode 100644
index 0000000..d0e5d47
--- /dev/null
+++ b/sysdeps/x86_64/dl-irel.h
@@ -0,0 +1,44 @@
+/* Machine-dependent ELF indirect relocation inline functions.
+   x86-64 version.
+   Copyright (C) 2009 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef dl_irel_h
+#define dl_irel_h
+
+#include <unistd.h>
+
+#define ELF_MACHINE_IRELA	1
+
+static inline void
+__attribute ((always_inline))
+elf_irela (const Elf64_Rela *reloc)
+{
+  Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
+  const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info);
+
+  if (__builtin_expect (r_type == R_X86_64_IRELATIVE, 1))
+    {
+      Elf64_Addr value = ((Elf64_Addr (*) (void)) reloc->r_addend) ();
+      *reloc_addr = value;
+    }
+  else
+    _exit (-1);
+}
+
+#endif /* !dl_irel_h */
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index 4444ae0..1b5ce8e 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -297,6 +297,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
 			  : (Elf64_Addr) sym_map->l_addr + sym->st_value);
 
       if (sym != NULL
+	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
 	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
 			       0))
 	value = ((Elf64_Addr (*) (void)) value) ();
@@ -442,6 +443,11 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
 	    }
 	  break;
 #  endif
+	case R_X86_64_IRELATIVE:
+	  value = map->l_addr + reloc->r_addend;
+	  value = ((Elf64_Addr (*) (void)) value) ();
+	  *reloc_addr = value;
+	  break;
 	default:
 	  _dl_reloc_bad_type (map, r_type, 0);
 	  break;
@@ -488,6 +494,12 @@ elf_machine_lazy_rel (struct link_map *map,
       td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
 			  + map->l_addr);
     }
+  else if (__builtin_expect (r_type == R_X86_64_IRELATIVE, 0))
+    {
+      Elf64_Addr value = map->l_addr + reloc->r_addend;
+      value = ((Elf64_Addr (*) (void)) value) ();
+      *reloc_addr = value;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }


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