PATCH: Make STT_GNU_IFUNC symbol dynamic

H.J. Lu hjl.tools@gmail.com
Sun May 24 00:39:00 GMT 2009


On Sat, May 23, 2009 at 04:54:37PM -0700, H.J. Lu wrote:
> On Sat, May 23, 2009 at 2:44 PM, Ulrich Drepper <drepper@redhat.com> wrote:
> > -----BEGIN PGP SIGNED MESSAGE-----
> > Hash: SHA1
> >
> > H.J. Lu wrote:
> >> Which tool will generate the new relocation? Will it be internal to linker.
> >
> > The code the compiler generates contains ordinary calls.  The assembler
> > will have to refrain from optimizing calls to static IFUNC functions.
> 
> Assembler will always generate PLT relocation for @PLT. I don't think
> we need to change the assembler.
> 
> > But the real logic is entirely internal to the static linker.  For every
> > local IFUNC symbol create a PLT slot.  This slot has no global symbol
> > attached and the relocation should be R_*_IRELATIVE (my proposed name).
> >  This relocation works like a R_*_RELATIVE relocation but it uses the
> > return value as for SHT_GNU_IFUNC symbols.  The reason we need such a
> > relocation is that we have no symbol at runtime.  We cannot use a normal
> > PLT slot relocation since this would perform a global name lookup, which
> > is wrong.  The R_*_IRELATIVE relocation is also more efficient.
> >
> >
> 
> I took a look. It isn't hard to implement. Should it be R_*_IJUMP_SLOT
> since it will be processed closer to R_*_JUMP_SLOT than R_*_RELATIVE?
> My linker only patch for x86-64 is ready for test. I just need to
> verify it works
> with glibc on x86-64.
> 

This patch works with the modified glibc. I am also enclosing
glibc patch for reference.


H.J.
---
bfd/

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

	* elf64-x86-64.c (elf64_x86_64_finish_dynamic_symbol): Generate
	R_X86_64_IJUMP_SLOT relocation for local STT_GNU_IFUNC symbol.

	* elflink.c (_bfd_elf_symbol_refs_local_p): Return FALSE on
	STT_GNU_IFUNC symbol.
	(_bfd_elf_link_hash_hide_symbol): Don't clean plt on
	STT_GNU_IFUNC symbol.

include/elf/

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

	* x86-64.h (R_X86_64_IJUMP_SLOT): New.

Index: bfd/elflink.c
===================================================================
--- bfd/elflink.c	(revision 5932)
+++ bfd/elflink.c	(working copy)
@@ -2845,6 +2845,10 @@ _bfd_elf_symbol_refs_local_p (struct elf
   if (h == NULL)
     return TRUE;
 
+  /* STT_GNU_IFUNC symbol must go through PLT.  */
+  if (h->type == STT_GNU_IFUNC)
+    return FALSE;
+
   /* STV_HIDDEN or STV_INTERNAL ones must be local.  */
   if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
       || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
@@ -6669,8 +6673,12 @@ _bfd_elf_link_hash_hide_symbol (struct b
 				struct elf_link_hash_entry *h,
 				bfd_boolean force_local)
 {
-  h->plt = elf_hash_table (info)->init_plt_offset;
-  h->needs_plt = 0;
+  /* STT_GNU_IFUNC symbol must go through PLT.  */
+  if (ELF_ST_TYPE (h->type) != STT_GNU_IFUNC)
+    {
+      h->plt = elf_hash_table (info)->init_plt_offset;
+      h->needs_plt = 0;
+    }
   if (force_local)
     {
       h->forced_local = 1;
Index: bfd/elf64-x86-64.c
===================================================================
--- bfd/elf64-x86-64.c	(revision 5933)
+++ bfd/elf64-x86-64.c	(working copy)
@@ -3328,7 +3328,10 @@ elf64_x86_64_finish_dynamic_symbol (bfd 
 
       /* This symbol has an entry in the procedure linkage table.  Set
 	 it up.	 */
-      if (h->dynindx == -1
+      if ((h->dynindx == -1
+	   && !(h->forced_local
+		&& h->def_regular
+		&& ELF_ST_TYPE (h->type) == STT_GNU_IFUNC))
 	  || htab->splt == NULL
 	  || htab->sgotplt == NULL
 	  || htab->srelplt == NULL)
@@ -3381,8 +3384,18 @@ elf64_x86_64_finish_dynamic_symbol (bfd 
       rela.r_offset = (htab->sgotplt->output_section->vma
 		       + htab->sgotplt->output_offset
 		       + got_offset);
-      rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
-      rela.r_addend = 0;
+      if (h->dynindx != -1)
+	{
+	  rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
+	  rela.r_addend = 0;
+	}
+      else
+	{
+	  rela.r_info = ELF64_R_INFO (0, R_X86_64_IJUMP_SLOT);
+	  rela.r_addend = (h->root.u.def.value
+			   + h->root.u.def.section->output_section->vma
+			   + h->root.u.def.section->output_offset);
+	}
       loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela);
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
 
Index: include/elf/x86-64.h
===================================================================
--- include/elf/x86-64.h	(revision 5933)
+++ include/elf/x86-64.h	(working copy)
@@ -71,6 +71,7 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_ty
      RELOC_NUMBER (R_X86_64_TLSDESC_CALL, 35) /* Relaxable call through TLS
 						 descriptor.  */
      RELOC_NUMBER (R_X86_64_TLSDESC, 36)      /* 2x64-bit TLS descriptor.  */
+     RELOC_NUMBER (R_X86_64_IJUMP_SLOT,37)      /* Create indirect PLT entry */
      RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250)       /* GNU C++ hack  */
      RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251)         /* GNU C++ hack  */
 END_RELOC_NUMBERS (R_X86_64_max)
-------------- next part --------------
diff --git a/elf/elf.h b/elf/elf.h
index 062ef00..e13001d 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -2625,8 +2625,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_IJUMP_SLOT	37	/* Create indirect PLT entry */
 
-#define R_X86_64_NUM		37
+#define R_X86_64_NUM		38
 
 
 /* AM33 relocations.  */
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index 4444ae0..8878dd0 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,12 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
 	    }
 	  break;
 #  endif
+	case R_X86_64_IJUMP_SLOT:
+	  value = map->l_addr + reloc->r_addend;
+	  value = ((DL_FIXUP_VALUE_TYPE (*) (void))
+		   DL_FIXUP_VALUE_ADDR (value)) ();
+	  *reloc_addr = value;
+	  break;
 	default:
 	  _dl_reloc_bad_type (map, r_type, 0);
 	  break;
@@ -488,6 +495,13 @@ 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_IJUMP_SLOT, 0))
+    {
+      Elf64_Addr value = map->l_addr + reloc->r_addend;
+      value = ((DL_FIXUP_VALUE_TYPE (*) (void))
+	       DL_FIXUP_VALUE_ADDR (value)) ();
+      *reloc_addr = value;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }


More information about the Binutils mailing list