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


Here is the updated linker patch for STT_GNU_IFUNC. It supports
STT_GNU_IFUNC symbols in shared library, dynamic executable and
static executable. OK for trunk?

Thanks.



H.J.
----
bfd/

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

	PR ld/10205
	* elf-bfd.h (SYMBOL_CALLS_LOCAL): FASLE on STT_GNU_IFUNC
	symbol.
	(struct bfd_elf_section_data): Remove indirect_relocs.
	(_bfd_elf_make_ifunc_reloc_section): Removed.
	(_bfd_elf_is_ifunc_symbol): Likewise.
	(_bfd_elf_create_static_ifunc_sections): New.
	(WILL_CALL_FINISH_DYNAMIC_SYMBOL): Return TRUE for
	STT_GNU_IFUNC symbol.

	* elf32-i386.c (elf_howto_table): Add R_386_IRELATIVE.
	(elf_i386_reloc_type_lookup): Likewise.
	(R_386_tls): Removed.
	(R_386_irelative): New.
	(R_386_vt_offset): Updated.
	(elf_i386_rtype_to_howto): Likewise.
	(elf_i386_link_hash_table): Add igotplt, iplt and irelplt.
	(elf_i386_link_hash_table_create): Initialize igotplt,
	iplt and irelplt.
	(elf_i386_check_relocs): Call _bfd_elf_create_static_ifunc_sections
	instead of _bfd_elf_make_ifunc_reloc_section.  Set up igotplt,
	iplt and irelplt.
	(elf_i386_allocate_dynrelocs): Use .iplt, .igot.plt and .rel.iplt
	sections for STT_GNU_IFUNC symbols in static executable.  Discard
	space for relocations against forced local STT_GNU_IFUNC symbols.
	Don't use indirect_relocs.
	(elf_i386_size_dynamic_sections): Set up .iplt and .igot.plt
	sections.
	(elf_i386_relocate_section): If an STT_GNU_IFUNC symbol is
	locally defined, resolve it to its PLT entry.  Remove check
	for STT_GNU_IFUNC symbols.
	(elf_i386_finish_dynamic_symbol): When building a static
	executable, use .iplt, .igot.plt and .rel.iplt sections for
	STT_GNU_IFUNC symbols.  Generate R_386_IRELATIVE relocation for
	locally defined STT_GNU_IFUNC symbol.

	* elf64-x86-64.c (x86_64_elf_howto): Add R_X86_64_IRELATIVE.
	(x86_64_reloc_map): Likewise.
	(R_X86_64_standard): Updated.
	(elf64_x86_64_link_hash_table): Add igotplt, iplt and irelplt.
	(elf64_x86_64_link_hash_table_create): Initialize igotplt,
	iplt and irelplt.
	(elf64_x86_64_check_relocs): Call _bfd_elf_create_ifunc_sections
	instead of _bfd_elf_make_ifunc_reloc_section.  Set up igotplt,
	iplt and irelplt.
	(elf64_x86_64_allocate_dynrelocs): Use .iplt, .igot.plt and
	.rela.iplt sections for STT_GNU_IFUNC symbols in static
	executable.  Discard space for relocations against forced
	local STT_GNU_IFUNC symbols
	for not building shared library.  Don't use indirect_relocs.
	(elf64_x86_64_size_dynamic_sections): Set up .iplt and .igot.plt
	sections.
	(elf64_x86_64_relocate_section): If an STT_GNU_IFUNC symbol is
	defined in executable, resolve it to its PLT entry and make sure
	it is reachable.  Remove check for STT_GNU_IFUNC symbols.
	(elf64_x86_64_finish_dynamic_symbol): When building a static
	executable, use .iplt, .igot.plt and .rela.iplt sections for
	STT_GNU_IFUNC symbols.  Generate R_X86_64_IRELATIVE relocation
	for locally defined STT_GNU_IFUNC symbol.

	* elflink.c (_bfd_elf_adjust_dynamic_symbol): Move STT_GNU_IFUNC
	symbol check to ...
	(elf_link_add_object_symbols): Here.
	(_bfd_elf_link_hash_hide_symbol): Don't clean plt on
	STT_GNU_IFUNC symbol.
	(elf_link_output_extsym): Always call
	elf_backend_finish_dynamic_symbol for STT_GNU_IFUNC symbol.
	(IFUNC_INFIX): Removed.
	(get_ifunc_reloc_section_name): Likewise.
	(_bfd_elf_make_ifunc_reloc_section): Likewise.
	(_bfd_elf_is_ifunc_symbol): Likewise.
	(_bfd_elf_create_static_ifunc_sections): New.

	* reloc.c (BFD_RELOC_386_IRELATIVE): New.
	(BFD_RELOC_X86_64_IRELATIVE): Likewise.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Likewise.

include/elf/

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

	PR ld/10205
	* i386.h (R_386_IRELATIVE): New.
	* x86-64.h (R_X86_64_IRELATIVE): Likewise.

ld/

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

	PR ld/10205
	* scripttempl/elf.sc (PLT): Add "*(.iplt)".
	(GOT): Add "*(.igot.plt)a" and "*(.igot)".
	(GOTPLT): Add "*(.igot)".
	(__rel_iplt_start): New.
	(__rel_iplt_end): Likewise.
	(__rela_iplt_start): Likewise.
	(__rela_iplt_end): Likewise.

ld/testsuite/

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

	PR ld/10205
	* ld-ifunc/ifunc.exp (contains_irelative_reloc): New.
	Use it on executable and shared library.
	Run *.d.

	* ld-ifunc/lib.c: Add a hidden alias, __GI_library_func2, for
	library_func2.
	(library_func): New.

	* ld-ifunc/ifunc-1-x86.d: New.
	* ld-ifunc/ifunc-1-x86.s: Likewise.
	* ld-ifunc/ifunc-2-i386.d: Likewise.
	* ld-ifunc/ifunc-2-i386.s: Likewise.
	* ld-ifunc/ifunc-2-x86-64.d: Likewise.
	* ld-ifunc/ifunc-2-x86-64.s: Likewise.

diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc \
		../binutils/src binutils
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/bfd-in2.h binutils/bfd/bfd-in2.h
--- ../binutils/src/bfd/bfd-in2.h	2009-05-26 15:19:00.000000000 -0700
+++ binutils/bfd/bfd-in2.h	2009-05-27 12:55:07.000000000 -0700
@@ -2840,6 +2840,7 @@ relaxation.  */
   BFD_RELOC_386_TLS_GOTDESC,
   BFD_RELOC_386_TLS_DESC_CALL,
   BFD_RELOC_386_TLS_DESC,
+  BFD_RELOC_386_IRELATIVE,
 
 /* x86-64/elf relocations  */
   BFD_RELOC_X86_64_GOT32,
@@ -2868,6 +2869,7 @@ relaxation.  */
   BFD_RELOC_X86_64_GOTPC32_TLSDESC,
   BFD_RELOC_X86_64_TLSDESC_CALL,
   BFD_RELOC_X86_64_TLSDESC,
+  BFD_RELOC_X86_64_IRELATIVE,
 
 /* ns32k relocations  */
   BFD_RELOC_NS32K_IMM_8,
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf32-i386.c binutils/bfd/elf32-i386.c
--- ../binutils/src/bfd/elf32-i386.c	2009-05-29 11:30:37.000000000 -0700
+++ binutils/bfd/elf32-i386.c	2009-05-29 13:09:46.000000000 -0700
@@ -138,10 +138,13 @@ static reloc_howto_type elf_howto_table[
   HOWTO(R_386_TLS_DESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
 	bfd_elf_generic_reloc, "R_386_TLS_DESC",
 	TRUE, 0xffffffff, 0xffffffff, FALSE),
+  HOWTO(R_386_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+	bfd_elf_generic_reloc, "R_386_IRELATIVE",
+	TRUE, 0xffffffff, 0xffffffff, FALSE),
 
   /* Another gap.  */
-#define R_386_tls (R_386_TLS_DESC + 1 - R_386_tls_offset)
-#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_tls)
+#define R_386_irelative (R_386_IRELATIVE + 1 - R_386_tls_offset)
+#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_irelative)
 
 /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_386_GNU_VTINHERIT,	/* type */
@@ -316,6 +319,10 @@ elf_i386_reloc_type_lookup (bfd *abfd AT
       TRACE ("BFD_RELOC_386_TLS_DESC");
       return &elf_howto_table[R_386_TLS_DESC - R_386_tls_offset];
 
+    case BFD_RELOC_386_IRELATIVE:
+      TRACE ("BFD_RELOC_386_IRELATIVE");
+      return &elf_howto_table[R_386_IRELATIVE];
+
     case BFD_RELOC_VTABLE_INHERIT:
       TRACE ("BFD_RELOC_VTABLE_INHERIT");
       return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset];
@@ -355,9 +362,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsi
       && ((indx = r_type - R_386_ext_offset) - R_386_standard
 	  >= R_386_ext - R_386_standard)
       && ((indx = r_type - R_386_tls_offset) - R_386_ext
-	  >= R_386_tls - R_386_ext)
-      && ((indx = r_type - R_386_vt_offset) - R_386_tls
-	  >= R_386_vt - R_386_tls))
+	  >= R_386_irelative - R_386_ext)
+      && ((indx = r_type - R_386_vt_offset) - R_386_irelative
+	  >= R_386_vt - R_386_irelative))
     {
       (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
 			     abfd, (int) r_type);
@@ -668,6 +675,9 @@ struct elf_i386_link_hash_table
   asection *srelplt;
   asection *sdynbss;
   asection *srelbss;
+  asection *igotplt;
+  asection *iplt;
+  asection *irelplt;
 
   /* The (unloaded but important) .rel.plt.unloaded section on VxWorks.  */
   asection *srelplt2;
@@ -764,6 +774,9 @@ elf_i386_link_hash_table_create (bfd *ab
   ret->srelplt = NULL;
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
+  ret->igotplt= NULL;
+  ret->iplt = NULL;
+  ret->irelplt= NULL;
   ret->tls_ldm_got.refcount = 0;
   ret->next_tls_desc_index = 0;
   ret->sgotplt_jump_table_size = 0;
@@ -1406,7 +1419,9 @@ elf_i386_check_relocs (bfd *abfd,
 
 	case R_386_32:
 	case R_386_PC32:
-	  if (h != NULL && !info->shared)
+	  /* STT_GNU_IFUNC symbol must go through PLT.  */
+	  if (h != NULL
+	      && (!info->shared || h->type == STT_GNU_IFUNC))
 	    {
 	      /* If this reloc is in a read-only section, we might
 		 need a copy reloc.  We can't check reliably at this
@@ -1475,11 +1490,30 @@ elf_i386_check_relocs (bfd *abfd,
 		  if (sreloc == NULL)
 		    return FALSE;
 
-		  /* Create the ifunc section as well, even if we have not encountered a
-		     indirect function symbol yet.  We may not even see one in the input
-		     object file, but we can still encounter them in libraries.  */
-		  (void) _bfd_elf_make_ifunc_reloc_section
-		    (abfd, sec, htab->elf.dynobj, 2);
+		  /* Create the ifunc section for static executables.
+		     If we never see an indirect function symbol nor
+		     we are building a static executable, those sections
+		     will be empty and won't appear in output.  */
+		  if (!info->shared)
+		    {
+		      if (!_bfd_elf_create_static_ifunc_sections (abfd,
+								  info))
+			return FALSE;
+
+		      if (htab->iplt == NULL)
+			{
+			  htab->iplt = bfd_get_section_by_name (abfd,
+								".iplt");
+			  htab->irelplt = bfd_get_section_by_name (abfd,
+								   ".rel.iplt");
+			  htab->igotplt = bfd_get_section_by_name (abfd,
+								   ".igot.plt");
+			  if (!htab->iplt
+			      || !htab->irelplt
+			      || !htab->igotplt)
+			    abort ();
+			}
+		    }
 		}
 
 	      /* If this is a global symbol, we count the number of
@@ -1822,7 +1856,6 @@ elf_i386_allocate_dynrelocs (struct elf_
   struct elf_i386_link_hash_table *htab;
   struct elf_i386_link_hash_entry *eh;
   struct elf_i386_dyn_relocs *p;
-  bfd_boolean use_indirect_section = FALSE;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -1909,6 +1942,28 @@ elf_i386_allocate_dynrelocs (struct elf_
 	  h->needs_plt = 0;
 	}
     }
+  else if (h->type == STT_GNU_IFUNC
+	   && !htab->elf.dynamic_sections_created)
+    {
+      /* When building a static executable, use .iplt, .igot.plt and
+	 .rel.iplt sections for STT_GNU_IFUNC symbols.  */
+      BFD_ASSERT (info->executable
+		  && !info->shared
+		  && htab->splt == NULL
+		  && htab->iplt != NULL);
+
+      h->plt.offset = htab->iplt->size;
+
+      /* Make room for this entry in the .iplt section.  */
+      htab->iplt->size += PLT_ENTRY_SIZE;
+
+      /* We also need to make an entry in the .got.iplt section, which
+	 will be placed in the .igot section by the linker script.  */
+      htab->igotplt->size += 4;
+
+      /* We also need to make an entry in the .rel.iplt section.  */
+      htab->irelplt->size += sizeof (Elf32_External_Rel);
+    }
   else
     {
       h->plt.offset = (bfd_vma) -1;
@@ -2044,16 +2099,6 @@ elf_i386_allocate_dynrelocs (struct elf_
 	    }
 	}
     }
-  else if (_bfd_elf_is_ifunc_symbol (info->output_bfd, h)
-	   && h->dynindx == -1
-	   && ! h->forced_local)
-    {
-      if (bfd_elf_link_record_dynamic_symbol (info, h)
-	  && h->dynindx != -1)
-	use_indirect_section = TRUE;
-      else
-	return FALSE;
-    }
   else if (ELIMINATE_COPY_RELOCS)
     {
       /* For the non-shared case, discard space for relocs against
@@ -2087,15 +2132,21 @@ elf_i386_allocate_dynrelocs (struct elf_
     keep: ;
     }
 
+  /* No need for dynamic relocation for local STT_GNU_IFUNC symbol.
+     Discard space for relocations against them.  */
+  if (h->type == STT_GNU_IFUNC
+      && (h->dynindx == -1 || h->forced_local))
+    {
+      eh->dyn_relocs = NULL;
+      return TRUE;
+    }
+
   /* Finally, allocate space.  */
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
       asection *sreloc;
 
-      if (use_indirect_section)
-	sreloc = elf_section_data (p->sec)->indirect_relocs;
-      else
- 	sreloc = elf_section_data (p->sec)->sreloc;
+      sreloc = elf_section_data (p->sec)->sreloc;
 
       BFD_ASSERT (sreloc != NULL);
       sreloc->size += p->count * sizeof (Elf32_External_Rel);
@@ -2299,6 +2350,8 @@ elf_i386_size_dynamic_sections (bfd *out
       if (s == htab->splt
 	  || s == htab->sgot
 	  || s == htab->sgotplt
+	  || s == htab->iplt
+	  || s == htab->igotplt
 	  || s == htab->sdynbss)
 	{
 	  /* Strip this section if we don't need it; see the
@@ -2589,7 +2642,7 @@ elf_i386_relocate_section (bfd *output_b
 	  && ((indx = r_type - R_386_ext_offset) - R_386_standard
 	      >= R_386_ext - R_386_standard)
 	  && ((indx = r_type - R_386_tls_offset) - R_386_ext
-	      >= R_386_tls - R_386_ext))
+	      >= R_386_irelative - R_386_ext))
 	{
 	  (*_bfd_error_handler)
 	    (_("%B: unrecognized relocation (0x%x) in section `%A'"),
@@ -2893,18 +2946,27 @@ elf_i386_relocate_section (bfd *output_b
 	      || is_vxworks_tls)
 	    break;
 
+	  if (h != NULL
+	      && h->def_regular
+	      && (h->forced_local || info->executable)
+	      && h->type == STT_GNU_IFUNC)
+	    {
+	      asection *plt = htab->splt ? htab->splt : htab->iplt;
+
+	      /* If an STT_GNU_IFUNC symbol is locally defined,
+		 resolve it to its PLT entry.  */
+	      relocation = (plt->output_section->vma
+			    + plt->output_offset
+			    + h->plt.offset);
+	      break;
+	    }
+
 	  if ((info->shared
 	       && (h == NULL
 		   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
 		   || h->root.type != bfd_link_hash_undefweak)
 	       && (r_type != R_386_PC32
 		   || !SYMBOL_CALLS_LOCAL (info, h)))
-	      || (! info->shared
-		  && h != NULL
-		  && h->dynindx != -1
-		  && ! h->forced_local
-		  && ((struct elf_i386_link_hash_entry *) h)->dyn_relocs != NULL
-		  && _bfd_elf_is_ifunc_symbol (output_bfd, h))
 	      || (ELIMINATE_COPY_RELOCS
 		  && !info->shared
 		  && h != NULL
@@ -2953,16 +3015,7 @@ elf_i386_relocate_section (bfd *output_b
 		  outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
 		}
 
-	      if (! info->shared
-		  && h != NULL
-		  && h->dynindx != -1
-		  && ! h->forced_local
-		  && _bfd_elf_is_ifunc_symbol (output_bfd, h)
-		  && elf_section_data (input_section)->indirect_relocs != NULL
-		  && elf_section_data (input_section)->indirect_relocs->contents != NULL)
-		sreloc = elf_section_data (input_section)->indirect_relocs;
-	      else
- 		sreloc = elf_section_data (input_section)->sreloc;
+	      sreloc = elf_section_data (input_section)->sreloc;
 
 	      BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
 
@@ -3667,37 +3720,67 @@ elf_i386_finish_dynamic_symbol (bfd *out
       bfd_vma got_offset;
       Elf_Internal_Rela rel;
       bfd_byte *loc;
+      asection *plt, *gotplt, *relplt;
+
+      /* When building a static executable, use .iplt, .igot.plt and
+	 .rel.iplt sections for STT_GNU_IFUNC symbols.  */
+      if (htab->splt != 0)
+	{
+	  plt = htab->splt;
+	  gotplt = htab->sgotplt;
+	  relplt = htab->srelplt;
+	}
+      else
+	{
+	  plt = htab->iplt;
+	  gotplt = htab->igotplt;
+	  relplt = htab->irelplt;
+	}
 
       /* This symbol has an entry in the procedure linkage table.  Set
 	 it up.  */
 
-      if (h->dynindx == -1
-	  || htab->splt == NULL
-	  || htab->sgotplt == NULL
-	  || htab->srelplt == NULL)
+      if ((h->dynindx == -1
+	   && !((h->forced_local || info->executable)
+		&& h->def_regular
+		&& h->type == STT_GNU_IFUNC))
+	  || plt == NULL
+	  || gotplt == NULL
+	  || relplt == NULL)
 	abort ();
 
       /* Get the index in the procedure linkage table which
 	 corresponds to this symbol.  This is the index of this symbol
 	 in all the symbols for which we are making plt entries.  The
-	 first entry in the procedure linkage table is reserved.  */
-      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+	 first entry in the procedure linkage table is reserved.
 
-      /* Get the offset into the .got table of the entry that
+	 Get the offset into the .got table of the entry that
 	 corresponds to this function.  Each .got entry is 4 bytes.
-	 The first three are reserved.  */
-      got_offset = (plt_index + 3) * 4;
+	 The first three are reserved.
+	 
+	 For static executables, we don't reserve anything.  */
+
+      if (plt == htab->splt)
+	{
+	  plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+	  got_offset = (plt_index + 3) * 4;
+	}
+      else
+	{
+	  plt_index = h->plt.offset / PLT_ENTRY_SIZE;
+	  got_offset = plt_index * 4;
+	}
 
       /* Fill in the entry in the procedure linkage table.  */
       if (! info->shared)
 	{
-	  memcpy (htab->splt->contents + h->plt.offset, elf_i386_plt_entry,
+	  memcpy (plt->contents + h->plt.offset, elf_i386_plt_entry,
 		  PLT_ENTRY_SIZE);
 	  bfd_put_32 (output_bfd,
-		      (htab->sgotplt->output_section->vma
-		       + htab->sgotplt->output_offset
+		      (gotplt->output_section->vma
+		       + gotplt->output_offset
 		       + got_offset),
-		      htab->splt->contents + h->plt.offset + 2);
+		      plt->contents + h->plt.offset + 2);
 
 	  if (htab->is_vxworks)
 	    {
@@ -3737,31 +3820,51 @@ elf_i386_finish_dynamic_symbol (bfd *out
 	}
       else
 	{
-	  memcpy (htab->splt->contents + h->plt.offset, elf_i386_pic_plt_entry,
+	  memcpy (plt->contents + h->plt.offset, elf_i386_pic_plt_entry,
 		  PLT_ENTRY_SIZE);
 	  bfd_put_32 (output_bfd, got_offset,
-		      htab->splt->contents + h->plt.offset + 2);
+		      plt->contents + h->plt.offset + 2);
 	}
 
-      bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
-		  htab->splt->contents + h->plt.offset + 7);
-      bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
-		  htab->splt->contents + h->plt.offset + 12);
+      /* Don't fill PLT entry for static executables.  */
+      if (plt == htab->splt)
+	{
+	  bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
+		      plt->contents + h->plt.offset + 7);
+	  bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
+		      plt->contents + h->plt.offset + 12);
+	}
 
       /* Fill in the entry in the global offset table.  */
       bfd_put_32 (output_bfd,
-		  (htab->splt->output_section->vma
-		   + htab->splt->output_offset
+		  (plt->output_section->vma
+		   + plt->output_offset
 		   + h->plt.offset
 		   + 6),
-		  htab->sgotplt->contents + got_offset);
+		  gotplt->contents + got_offset);
 
       /* Fill in the entry in the .rel.plt section.  */
-      rel.r_offset = (htab->sgotplt->output_section->vma
-		      + htab->sgotplt->output_offset
+      rel.r_offset = (gotplt->output_section->vma
+		      + gotplt->output_offset
 		      + got_offset);
-      rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
-      loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rel);
+      if (h->dynindx == -1
+	  || (info->executable
+	      && h->def_regular
+	       && h->type == STT_GNU_IFUNC))
+	{
+	  /* If an STT_GNU_IFUNC symbol is locally defined, generate
+	     R_386_IRELATIVE instead of R_386_JUMP_SLOT.  Store addend
+	     in the .got.plt section.  */
+	  bfd_put_32 (output_bfd,
+		      (h->root.u.def.value 
+		       + h->root.u.def.section->output_section->vma
+		       + h->root.u.def.section->output_offset),
+		      gotplt->contents + got_offset);
+	  rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
+	}
+      else
+	rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
+      loc = relplt->contents + plt_index * sizeof (Elf32_External_Rel);
       bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
 
       if (!h->def_regular)
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf64-x86-64.c binutils/bfd/elf64-x86-64.c
--- ../binutils/src/bfd/elf64-x86-64.c	2009-05-29 11:30:37.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c	2009-05-29 13:10:20.000000000 -0700
@@ -143,12 +143,15 @@ static reloc_howto_type x86_64_elf_howto
 	complain_overflow_bitfield, bfd_elf_generic_reloc,
 	"R_X86_64_TLSDESC",
 	FALSE, MINUS_ONE, MINUS_ONE, FALSE),
+  HOWTO(R_X86_64_IRELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
+	bfd_elf_generic_reloc, "R_X86_64_IRELATIVE", FALSE, MINUS_ONE,
+	MINUS_ONE, FALSE),
 
   /* We have a gap in the reloc numbers here.
      R_X86_64_standard counts the number up to this point, and
      R_X86_64_vt_offset is the value to subtract from a reloc type of
      R_X86_64_GNU_VT* to form an index into this table.  */
-#define R_X86_64_standard (R_X86_64_TLSDESC + 1)
+#define R_X86_64_standard (R_X86_64_IRELATIVE + 1)
 #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
 
 /* GNU extension to record C++ vtable hierarchy.  */
@@ -211,6 +214,7 @@ static const struct elf_reloc_map x86_64
   { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
   { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
   { BFD_RELOC_X86_64_TLSDESC,	R_X86_64_TLSDESC, },
+  { BFD_RELOC_X86_64_IRELATIVE,	R_X86_64_IRELATIVE, },
   { BFD_RELOC_VTABLE_INHERIT,	R_X86_64_GNU_VTINHERIT, },
   { BFD_RELOC_VTABLE_ENTRY,	R_X86_64_GNU_VTENTRY, },
 };
@@ -489,6 +493,9 @@ struct elf64_x86_64_link_hash_table
   asection *srelplt;
   asection *sdynbss;
   asection *srelbss;
+  asection *igotplt;
+  asection *iplt;
+  asection *irelplt;
 
   /* The offset into splt of the PLT entry for the TLS descriptor
      resolver.  Special values are 0, if not necessary (or not found
@@ -581,6 +588,9 @@ elf64_x86_64_link_hash_table_create (bfd
   ret->srelplt = NULL;
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
+  ret->igotplt= NULL;
+  ret->iplt = NULL;
+  ret->irelplt= NULL;
   ret->sym_sec.abfd = NULL;
   ret->tlsdesc_plt = 0;
   ret->tlsdesc_got = 0;
@@ -1230,7 +1240,9 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 	case R_X86_64_PC32:
 	case R_X86_64_PC64:
 	case R_X86_64_64:
-	  if (h != NULL && !info->shared)
+	  /* STT_GNU_IFUNC symbol must go through PLT.  */
+	  if (h != NULL
+	      && (!info->shared || h->type == STT_GNU_IFUNC))
 	    {
 	      /* If this reloc is in a read-only section, we might
 		 need a copy reloc.  We can't check reliably at this
@@ -1299,11 +1311,30 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 		  if (sreloc == NULL)
 		    return FALSE;
 
-		  /* Create the ifunc section, even if we will not encounter an
-		     indirect function symbol.  We may not even see one in the input
-		     object file, but we can still encounter them in libraries.  */
-		  (void) _bfd_elf_make_ifunc_reloc_section
-		    (abfd, sec, htab->elf.dynobj, 2);
+		  /* Create the ifunc section for static executables.
+		     If we never see an indirect function symbol nor
+		     we are building a static executable, those sections
+		     will be empty and won't appear in output.  */
+		  if (!info->shared)
+		    {
+		      if (!_bfd_elf_create_static_ifunc_sections (abfd,
+								  info))
+			return FALSE;
+
+		      if (htab->iplt == NULL)
+			{
+			  htab->iplt = bfd_get_section_by_name (abfd,
+								".iplt");
+			  htab->irelplt = bfd_get_section_by_name (abfd,
+								   ".rela.iplt");
+			  htab->igotplt = bfd_get_section_by_name (abfd,
+								   ".igot.plt");
+			  if (!htab->iplt
+			      || !htab->irelplt
+			      || !htab->igotplt)
+			    abort ();
+			}
+		    }
 		}
 
 	      /* If this is a global symbol, we count the number of
@@ -1659,7 +1690,6 @@ elf64_x86_64_allocate_dynrelocs (struct 
   struct elf64_x86_64_link_hash_table *htab;
   struct elf64_x86_64_link_hash_entry *eh;
   struct elf64_x86_64_dyn_relocs *p;
-  bfd_boolean use_indirect_section = FALSE;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -1723,6 +1753,28 @@ elf64_x86_64_allocate_dynrelocs (struct 
 	  h->needs_plt = 0;
 	}
     }
+  else if (h->type == STT_GNU_IFUNC
+	   && !htab->elf.dynamic_sections_created)
+    {
+      /* When building a static executable, use .iplt, .igot.plt and
+	 .rela.iplt sections for STT_GNU_IFUNC symbols.  */
+      BFD_ASSERT (info->executable
+		  && !info->shared
+		  && htab->splt == NULL
+		  && htab->iplt != NULL);
+
+      h->plt.offset = htab->iplt->size;
+
+      /* Make room for this entry in the .iplt section.  */
+      htab->iplt->size += PLT_ENTRY_SIZE;
+
+      /* We also need to make an entry in the .got.iplt section, which
+	 will be placed in the .igot section by the linker script.  */
+      htab->igotplt->size += GOT_ENTRY_SIZE;
+
+      /* We also need to make an entry in the .rela.iplt section.  */
+      htab->irelplt->size += sizeof (Elf64_External_Rela);
+    }
   else
     {
       h->plt.offset = (bfd_vma) -1;
@@ -1843,16 +1895,7 @@ elf64_x86_64_allocate_dynrelocs (struct 
 		   && ! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
 	}
-    }
-  else if (_bfd_elf_is_ifunc_symbol (info->output_bfd, h)
-	   && h->dynindx == -1
-	   && ! h->forced_local)
-    {
-      if (bfd_elf_link_record_dynamic_symbol (info, h)
-	  && h->dynindx != -1)
-	use_indirect_section = TRUE;
-      else
-	return FALSE;
+
     }
   else if (ELIMINATE_COPY_RELOCS)
     {
@@ -1885,15 +1928,21 @@ elf64_x86_64_allocate_dynrelocs (struct 
     keep: ;
     }
 
+  /* No need for dynamic relocation for local STT_GNU_IFUNC symbol.
+     Discard space for relocations against them.  */
+  if (h->type == STT_GNU_IFUNC
+      && (h->dynindx == -1 || h->forced_local))
+    {
+      eh->dyn_relocs = NULL;
+      return TRUE;
+    }
+
   /* Finally, allocate space.  */
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
       asection * sreloc;
-
-      if (use_indirect_section)
-	sreloc = elf_section_data (p->sec)->indirect_relocs;
-      else
-	sreloc = elf_section_data (p->sec)->sreloc;
+      
+      sreloc = elf_section_data (p->sec)->sreloc;
 
       BFD_ASSERT (sreloc != NULL);
 
@@ -2110,6 +2159,8 @@ elf64_x86_64_size_dynamic_sections (bfd 
       if (s == htab->splt
 	  || s == htab->sgot
 	  || s == htab->sgotplt
+	  || s == htab->iplt
+	  || s == htab->igotplt
 	  || s == htab->sdynbss)
 	{
 	  /* Strip this section if we don't need it; see the
@@ -2694,18 +2745,34 @@ elf64_x86_64_relocate_section (bfd *outp
 	  if ((input_section->flags & SEC_ALLOC) == 0)
 	    break;
 
+	  if (h != NULL
+	      && h->def_regular
+	      && (h->forced_local || info->executable)
+	      && h->type == STT_GNU_IFUNC)
+	    {
+	      asection *plt = htab->splt ? htab->splt : htab->iplt;
+
+	      /* If an STT_GNU_IFUNC symbol is locally defined,
+		 resolve it to its PLT entry and make sure it is
+		 reachable.  */
+	      BFD_ASSERT (h->plt.offset != (bfd_vma) -1
+			  && (r_type == R_X86_64_PC32
+			      || r_type == R_X86_64_PC64
+			      || r_type == R_X86_64_32
+			      || r_type == R_X86_64_64));
+
+	      relocation = (plt->output_section->vma
+			    + plt->output_offset
+			    + h->plt.offset);
+	      break;
+	    }
+
 	  if ((info->shared
 	       && (h == NULL
 		   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
 		   || h->root.type != bfd_link_hash_undefweak)
 	       && (! IS_X86_64_PCREL_TYPE (r_type)
 		   || ! SYMBOL_CALLS_LOCAL (info, h)))
-	      || (! info->shared
-		  && h != NULL
-		  && h->dynindx != -1
-		  && ! h->forced_local
-		  && ((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs != NULL
-		  && _bfd_elf_is_ifunc_symbol (output_bfd, h))
 	      || (ELIMINATE_COPY_RELOCS
 		  && !info->shared
 		  && h != NULL
@@ -2797,16 +2864,7 @@ elf64_x86_64_relocate_section (bfd *outp
 		    }
 		}
 
-	      if (! info->shared
-		  && h != NULL
-		  && h->dynindx != -1
-		  && ! h->forced_local
-		  && _bfd_elf_is_ifunc_symbol (output_bfd, h)
-		  && elf_section_data (input_section)->indirect_relocs != NULL
-		  && elf_section_data (input_section)->indirect_relocs->contents != NULL)
-		sreloc = elf_section_data (input_section)->indirect_relocs;
-	      else
-		sreloc = elf_section_data (input_section)->sreloc;
+	      sreloc = elf_section_data (input_section)->sreloc;
 
 	      BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
 
@@ -3315,28 +3373,58 @@ elf64_x86_64_finish_dynamic_symbol (bfd 
       bfd_vma got_offset;
       Elf_Internal_Rela rela;
       bfd_byte *loc;
+      asection *plt, *gotplt, *relplt;
+
+      /* When building a static executable, use .iplt, .igot.plt and
+	 .rel.iplt sections for STT_GNU_IFUNC symbols.  */
+      if (htab->splt != 0)
+	{
+	  plt = htab->splt;
+	  gotplt = htab->sgotplt;
+	  relplt = htab->srelplt;
+	}
+      else
+	{
+	  plt = htab->iplt;
+	  gotplt = htab->igotplt;
+	  relplt = htab->irelplt;
+	}
 
       /* This symbol has an entry in the procedure linkage table.  Set
 	 it up.	 */
-      if (h->dynindx == -1
-	  || htab->splt == NULL
-	  || htab->sgotplt == NULL
-	  || htab->srelplt == NULL)
+      if ((h->dynindx == -1
+	   && !((h->forced_local || info->executable)
+		&& h->def_regular
+		&& h->type == STT_GNU_IFUNC))
+	  || plt == NULL
+	  || gotplt == NULL
+	  || relplt == NULL)
 	abort ();
 
       /* Get the index in the procedure linkage table which
 	 corresponds to this symbol.  This is the index of this symbol
 	 in all the symbols for which we are making plt entries.  The
-	 first entry in the procedure linkage table is reserved.  */
-      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
-
-      /* Get the offset into the .got table of the entry that
+	 first entry in the procedure linkage table is reserved.
+	 
+	 Get the offset into the .got table of the entry that
 	 corresponds to this function.	Each .got entry is GOT_ENTRY_SIZE
-	 bytes. The first three are reserved for the dynamic linker.  */
-      got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
+	 bytes. The first three are reserved for the dynamic linker.
+
+	 For static executables, we don't reserve anything.  */
+
+      if (plt == htab->splt)
+	{
+	  plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+	  got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
+	}
+      else
+	{
+	  plt_index = h->plt.offset / PLT_ENTRY_SIZE;
+	  got_offset = plt_index * GOT_ENTRY_SIZE;
+	}
 
       /* Fill in the entry in the procedure linkage table.  */
-      memcpy (htab->splt->contents + h->plt.offset, elf64_x86_64_plt_entry,
+      memcpy (plt->contents + h->plt.offset, elf64_x86_64_plt_entry,
 	      PLT_ENTRY_SIZE);
 
       /* Insert the relocation positions of the plt section.  The magic
@@ -3345,35 +3433,55 @@ elf64_x86_64_finish_dynamic_symbol (bfd 
       /* Put offset for jmp *name@GOTPCREL(%rip), since the
 	 instruction uses 6 bytes, subtract this value.  */
       bfd_put_32 (output_bfd,
-		      (htab->sgotplt->output_section->vma
-		       + htab->sgotplt->output_offset
+		      (gotplt->output_section->vma
+		       + gotplt->output_offset
 		       + got_offset
-		       - htab->splt->output_section->vma
-		       - htab->splt->output_offset
+		       - plt->output_section->vma
+		       - plt->output_offset
 		       - h->plt.offset
 		       - 6),
-		  htab->splt->contents + h->plt.offset + 2);
-      /* Put relocation index.  */
-      bfd_put_32 (output_bfd, plt_index,
-		  htab->splt->contents + h->plt.offset + 7);
-      /* Put offset for jmp .PLT0.  */
-      bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
-		  htab->splt->contents + h->plt.offset + 12);
+		  plt->contents + h->plt.offset + 2);
+
+      /* Don't fill PLT entry for static executables.  */
+      if (plt == htab->splt)
+	{
+	  /* Put relocation index.  */
+	  bfd_put_32 (output_bfd, plt_index,
+		      plt->contents + h->plt.offset + 7);
+	  /* Put offset for jmp .PLT0.  */
+	  bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
+		      plt->contents + h->plt.offset + 12);
+	}
 
       /* Fill in the entry in the global offset table, initially this
 	 points to the pushq instruction in the PLT which is at offset 6.  */
-      bfd_put_64 (output_bfd, (htab->splt->output_section->vma
-			       + htab->splt->output_offset
+      bfd_put_64 (output_bfd, (plt->output_section->vma
+			       + plt->output_offset
 			       + h->plt.offset + 6),
-		  htab->sgotplt->contents + got_offset);
+		  gotplt->contents + got_offset);
 
       /* Fill in the entry in the .rela.plt section.  */
-      rela.r_offset = (htab->sgotplt->output_section->vma
-		       + htab->sgotplt->output_offset
+      rela.r_offset = (gotplt->output_section->vma
+		       + gotplt->output_offset
 		       + got_offset);
-      rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
-      rela.r_addend = 0;
-      loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela);
+      if (h->dynindx == -1
+	  || (info->executable
+	      && h->def_regular
+	      && h->type == STT_GNU_IFUNC))
+	{
+	  /* If an STT_GNU_IFUNC symbol is locally defined, generate
+	     R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT.  */
+	  rela.r_info = ELF64_R_INFO (0, R_X86_64_IRELATIVE);
+	  rela.r_addend = (h->root.u.def.value
+			   + h->root.u.def.section->output_section->vma
+			   + h->root.u.def.section->output_offset);
+	}
+      else
+	{
+	  rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
+	  rela.r_addend = 0;
+	}
+      loc = relplt->contents + plt_index * sizeof (Elf64_External_Rela);
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
 
       if (!h->def_regular)
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf-bfd.h binutils/bfd/elf-bfd.h
--- ../binutils/src/bfd/elf-bfd.h	2009-05-26 15:19:00.000000000 -0700
+++ binutils/bfd/elf-bfd.h	2009-05-29 11:42:47.000000000 -0700
@@ -229,9 +229,11 @@ struct elf_link_hash_entry
 #define SYMBOL_REFERENCES_LOCAL(INFO, H) \
   _bfd_elf_symbol_refs_local_p (H, INFO, 0)
 
-/* Will _calls_ to this symbol always call the version in this object?  */
+/* Will _calls_ to this symbol always call the version in this object?
+   STT_GNU_IFUNC symbol must go through PLT.  */
 #define SYMBOL_CALLS_LOCAL(INFO, H) \
-  _bfd_elf_symbol_refs_local_p (H, INFO, 1)
+  (((H) == NULL || (H)->type != STT_GNU_IFUNC)				\
+   && _bfd_elf_symbol_refs_local_p (H, INFO, 1))
 
 /* Common symbols that are turned into definitions don't have the
    DEF_REGULAR flag set, so they might appear to be undefined.  */
@@ -1299,9 +1301,6 @@ struct bfd_elf_section_data
   /* A pointer to the bfd section used for dynamic relocs.  */
   asection *sreloc;
 
-  /* A pointer to the bfd section used for dynamic relocs against ifunc symbols.  */
-  asection *indirect_relocs;
-
   union {
     /* Group name, if this section is a member of a group.  */
     const char *name;
@@ -2149,22 +2148,21 @@ extern int _bfd_elf_obj_attrs_arg_type (
 extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
 extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
 
-extern asection * _bfd_elf_make_ifunc_reloc_section
-  (bfd *, asection *, bfd *, unsigned int);
+extern bfd_boolean _bfd_elf_create_static_ifunc_sections
+  (bfd *, struct bfd_link_info *);
 
 /* Large common section.  */
 extern asection _bfd_elf_large_com_section;
 
-extern bfd_boolean _bfd_elf_is_ifunc_symbol
-  (bfd *, struct elf_link_hash_entry *);
-
 /* This is the condition under which finish_dynamic_symbol will be called.
    If our finish_dynamic_symbol isn't called, we'll need to do something
-   about initializing any .plt and .got entries in relocate_section.  */
+   about initializing any .plt and .got entries in relocate_section. 
+   STT_GNU_IFUNC symbol must go through PLT.  */
 #define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \
-  ((DYN)								\
-   && ((SHARED) || !(H)->forced_local)					\
-   && ((H)->dynindx != -1 || (H)->forced_local))
+  ((H)->type == STT_GNU_IFUNC						\
+   || ((DYN)								\
+       && ((SHARED) || !(H)->forced_local)				\
+       && ((H)->dynindx != -1 || (H)->forced_local)))
 
 /* This macro is to avoid lots of duplicated code in the body
    of xxx_relocate_section() in the various elfxx-xxxx.c files.  */
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elflink.c binutils/bfd/elflink.c
--- ../binutils/src/bfd/elflink.c	2009-05-26 15:19:00.000000000 -0700
+++ binutils/bfd/elflink.c	2009-05-29 11:42:47.000000000 -0700
@@ -2675,13 +2675,6 @@ _bfd_elf_adjust_dynamic_symbol (struct e
   dynobj = elf_hash_table (eif->info)->dynobj;
   bed = get_elf_backend_data (dynobj);
 
-
-  if (h->type == STT_GNU_IFUNC
-      && (bed->elf_osabi == ELFOSABI_LINUX
-	  /* GNU/Linux is still using the default value 0.  */
-	  || bed->elf_osabi == ELFOSABI_NONE))
-    h->needs_plt = 1;
-
   if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h))
     {
       eif->failed = TRUE;
@@ -4294,6 +4287,10 @@ elf_link_add_object_symbols (bfd *abfd, 
 
 	      h->type = ELF_ST_TYPE (isym->st_info);
 	    }
+      
+	  /* STT_GNU_IFUNC symbol must go through PLT.  */
+	  if (h->type == STT_GNU_IFUNC)
+	    h->needs_plt = 1;
 
 	  /* Merge st_other field.  */
 	  elf_merge_st_other (abfd, h, isym, definition, dynamic);
@@ -6669,8 +6666,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 (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;
@@ -8649,14 +8650,18 @@ elf_link_output_extsym (struct elf_link_
   /* Give the processor backend a chance to tweak the symbol value,
      and also to finish up anything that needs to be done for this
      symbol.  FIXME: Not calling elf_backend_finish_dynamic_symbol for
-     forced local syms when non-shared is due to a historical quirk.  */
-  if ((h->dynindx != -1
-       || h->forced_local)
-      && ((finfo->info->shared
-	   && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-	       || h->root.type != bfd_link_hash_undefweak))
-	  || !h->forced_local)
-      && elf_hash_table (finfo->info)->dynamic_sections_created)
+     forced local syms when non-shared is due to a historical quirk.
+     STT_GNU_IFUNC symbol must go through PLT.  */
+  if ((h->type == STT_GNU_IFUNC
+       && h->ref_regular
+       && !finfo->info->relocatable)
+      || ((h->dynindx != -1
+	   || h->forced_local)
+	  && ((finfo->info->shared
+	       && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+		   || h->root.type != bfd_link_hash_undefweak))
+	      || !h->forced_local)
+	  && elf_hash_table (finfo->info)->dynamic_sections_created))
     {
       if (! ((*bed->elf_backend_finish_dynamic_symbol)
 	     (finfo->output_bfd, finfo->info, h, &sym)))
@@ -12487,88 +12492,87 @@ _bfd_elf_make_dynamic_reloc_section (ase
   return reloc_sec;
 }
 
-/* Returns the name of the ifunc using dynamic reloc section associated with SEC.  */
-#define IFUNC_INFIX ".ifunc"
+/* Create sections needed by STT_GNU_IFUNC symbol for static
+   executables.  */
 
-static const char *
-get_ifunc_reloc_section_name (bfd *       abfd,
-			      asection *  sec)
+bfd_boolean
+_bfd_elf_create_static_ifunc_sections (bfd *abfd,
+				       struct bfd_link_info *info)
 {
-  const char *  dot;
-  char *  name;
-  const char *  base_name;
-  unsigned int  strndx = elf_elfheader (abfd)->e_shstrndx;
-  unsigned int  shnam = elf_section_data (sec)->rel_hdr.sh_name;
-
-  base_name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
-  if (base_name == NULL)
-    return NULL;
+  flagword flags, pltflags;
+  int ptralign;
+  asection *s;
+  const struct elf_backend_data *bed;
 
-  dot = strchr (base_name + 1, '.');
-  name = bfd_alloc (abfd, strlen (base_name) + strlen (IFUNC_INFIX) + 1);
-  sprintf (name, "%.*s%s%s", (int)(dot - base_name), base_name, IFUNC_INFIX, dot);
+  /* Should never be called for shared library.  */
+  BFD_ASSERT (!info->shared);
 
-  return name;
-}
-
-/* Like _bfd_elf_make_dynamic_reloc_section but it creates a
-   section for holding relocs against symbols with the STT_GNU_IFUNC
-   type.  The section is attached to the OWNER bfd but it is created
-   with a name based on SEC from ABFD.  */
+  /* This function may be called more than once.  */
+  s = bfd_get_section_by_name (abfd, ".iplt");
+  if (s != NULL)
+    return TRUE;
 
-asection *
-_bfd_elf_make_ifunc_reloc_section (bfd *         abfd,
-				   asection *    sec,
-				   bfd *         owner,
-				   unsigned int  align)
-{
-  asection * reloc_sec = elf_section_data (sec)->indirect_relocs;
+  bed = get_elf_backend_data (abfd);
 
-  if (reloc_sec == NULL)
-    {
-      const char * name = get_ifunc_reloc_section_name (abfd, sec);
+  /* We need to create .iplt, .rel[a].iplt, .igot, .igot.plt,  */
+  flags = bed->dynamic_sec_flags;
 
-      if (name == NULL)
-	return NULL;
+  pltflags = flags;
+  if (bed->plt_not_loaded)
+    /* We do not clear SEC_ALLOC here because we still want the OS to
+       allocate space for the section; it's just that there's nothing
+       to read in from the object file.  */
+    pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
+  else
+    pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD;
+  if (bed->plt_readonly)
+    pltflags |= SEC_READONLY;
 
-      reloc_sec = bfd_get_section_by_name (owner, name);
+  s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
+  if (s == NULL
+      || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
+    return FALSE;
 
-      if (reloc_sec == NULL)
-	{
-	  flagword flags;
+  s = bfd_make_section_with_flags (abfd,
+				   (bed->rela_plts_and_copies_p
+				    ? ".rela.iplt" : ".rel.iplt"),
+				   flags | SEC_READONLY);
+  if (s == NULL
+      || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+    return FALSE;
 
-	  flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-	  if ((sec->flags & SEC_ALLOC) != 0)
-	    flags |= SEC_ALLOC | SEC_LOAD;
+  switch (bed->s->arch_size)
+    {
+    case 32:
+      ptralign = 2;
+      break;
 
-	  reloc_sec = bfd_make_section_with_flags (owner, name, flags);
-	  
-	  if (reloc_sec != NULL
-	      && ! bfd_set_section_alignment (owner, reloc_sec, align))
-	    reloc_sec = NULL;
-	}
+    case 64:
+      ptralign = 3;
+      break;
 
-      elf_section_data (sec)->indirect_relocs = reloc_sec;
+    default:
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
     }
 
-  return reloc_sec;
-}
-
-/* Returns true if the hash entry refers to a symbol marked for
-   indirect handling during reloc processing.  */
-
-bfd_boolean
-_bfd_elf_is_ifunc_symbol (bfd *abfd, struct elf_link_hash_entry *h)
-{
-  const struct elf_backend_data * bed;
-
-  if (abfd == NULL || h == NULL)
-    return FALSE;
+  /* We don't need the .igot section if we have the .igot.plt
+     section.  */
 
-  bed = get_elf_backend_data (abfd);
+  if (bed->want_got_plt)
+    {
+      s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
+      if (s == NULL
+	  || !bfd_set_section_alignment (abfd, s, ptralign))
+	return FALSE;
+    }
+  else
+    {
+      s = bfd_make_section_with_flags (abfd, ".igot", flags);
+      if (s == NULL
+	  || !bfd_set_section_alignment (abfd, s, ptralign))
+	return FALSE;
+    }
 
-  /* GNU/Linux is still using the default value ELFOSABI_NONE.  */
-  return (h->type == STT_GNU_IFUNC
-	  && (bed->elf_osabi == ELFOSABI_LINUX
-	      || bed->elf_osabi == ELFOSABI_NONE));
+  return TRUE;
 }
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/libbfd.h binutils/bfd/libbfd.h
--- ../binutils/src/bfd/libbfd.h	2009-05-05 10:56:24.000000000 -0700
+++ binutils/bfd/libbfd.h	2009-05-26 22:01:39.000000000 -0700
@@ -1104,6 +1104,7 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_386_TLS_GOTDESC",
   "BFD_RELOC_386_TLS_DESC_CALL",
   "BFD_RELOC_386_TLS_DESC",
+  "BFD_RELOC_386_IRELATIVE",
   "BFD_RELOC_X86_64_GOT32",
   "BFD_RELOC_X86_64_PLT32",
   "BFD_RELOC_X86_64_COPY",
@@ -1130,6 +1131,7 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_X86_64_GOTPC32_TLSDESC",
   "BFD_RELOC_X86_64_TLSDESC_CALL",
   "BFD_RELOC_X86_64_TLSDESC",
+  "BFD_RELOC_X86_64_IRELATIVE",
   "BFD_RELOC_NS32K_IMM_8",
   "BFD_RELOC_NS32K_IMM_16",
   "BFD_RELOC_NS32K_IMM_32",
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/reloc.c binutils/bfd/reloc.c
--- ../binutils/src/bfd/reloc.c	2009-05-28 13:34:46.000000000 -0700
+++ binutils/bfd/reloc.c	2009-05-28 13:40:43.000000000 -0700
@@ -2492,6 +2492,8 @@ ENUMX
   BFD_RELOC_386_TLS_DESC_CALL
 ENUMX
   BFD_RELOC_386_TLS_DESC
+ENUMX
+  BFD_RELOC_386_IRELATIVE
 ENUMDOC
   i386/elf relocations
 
@@ -2547,6 +2549,8 @@ ENUMX
   BFD_RELOC_X86_64_TLSDESC_CALL
 ENUMX
   BFD_RELOC_X86_64_TLSDESC
+ENUMX
+  BFD_RELOC_X86_64_IRELATIVE
 ENUMDOC
   x86-64/elf relocations
 
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/include/elf/i386.h binutils/include/elf/i386.h
--- ../binutils/src/include/elf/i386.h	2009-05-05 10:56:16.000000000 -0700
+++ binutils/include/elf/i386.h	2009-05-23 18:06:03.000000000 -0700
@@ -66,6 +66,7 @@ START_RELOC_NUMBERS (elf_i386_reloc_type
      RELOC_NUMBER (R_386_TLS_GOTDESC,  39)
      RELOC_NUMBER (R_386_TLS_DESC_CALL,40)
      RELOC_NUMBER (R_386_TLS_DESC,     41)
+     RELOC_NUMBER (R_386_IRELATIVE,    42) /* Adjust indirectly by program base */
 
      /* Used by Intel.  */
      RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200)
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/include/elf/x86-64.h binutils/include/elf/x86-64.h
--- ../binutils/src/include/elf/x86-64.h	2009-05-05 10:56:16.000000000 -0700
+++ binutils/include/elf/x86-64.h	2009-05-26 22:01:38.000000000 -0700
@@ -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_IRELATIVE, 37)    /* Adjust indirectly by program base */
      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)
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/scripttempl/elf.sc binutils/ld/scripttempl/elf.sc
--- ../binutils/src/ld/scripttempl/elf.sc	2009-05-05 10:55:58.000000000 -0700
+++ binutils/ld/scripttempl/elf.sc	2009-05-27 22:40:11.000000000 -0700
@@ -113,15 +113,15 @@ if test -z "${INITIAL_READONLY_SECTIONS}
   INITIAL_READONLY_SECTIONS=".interp       ${RELOCATING-0} : { *(.interp) }"
 fi
 if test -z "$PLT"; then
-  PLT=".plt          ${RELOCATING-0} : { *(.plt) }"
+  PLT=".plt          ${RELOCATING-0} : { *(.plt) *(.iplt)}"
 fi
 test -n "${DATA_PLT-${BSS_PLT-text}}" && TEXT_PLT=yes
 if test -z "$GOT"; then
   if test -z "$SEPARATE_GOTPLT"; then
-    GOT=".got          ${RELOCATING-0} : { *(.got.plt) *(.got) }"
+    GOT=".got          ${RELOCATING-0} : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }"
   else
-    GOT=".got          ${RELOCATING-0} : { *(.got) }"
-    GOTPLT=".got.plt      ${RELOCATING-0} : { *(.got.plt) }"
+    GOT=".got          ${RELOCATING-0} : { *(.got) *(.igot) }"
+    GOTPLT=".got.plt      ${RELOCATING-0} : { *(.got.plt)  *(.igot.plt) }"
   fi
 fi
 DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
@@ -354,8 +354,20 @@ EOF
 fi
 
 cat >> ldscripts/dyntmp.$$ <<EOF
-  .rel.plt      ${RELOCATING-0} : { *(.rel.plt) }
-  .rela.plt     ${RELOCATING-0} : { *(.rela.plt) }
+  .rel.plt      ${RELOCATING-0} :
+    {
+      *(.rel.plt)
+      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__rel_iplt_start = .);}}
+      *(.rel.iplt)
+      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__rel_iplt_end = .);}}
+    }
+  .rela.plt     ${RELOCATING-0} :
+    {
+      *(.rela.plt)
+      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__rela_iplt_start = .);}}
+      *(.rela.iplt)
+      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__rela_iplt_end = .);}}
+    }
   ${OTHER_PLT_RELOC_SECTIONS}
 EOF
 
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.d binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.d
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.d	1969-12-31 16:00:00.000000000 -0800
+++ binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.d	2009-05-24 19:12:28.000000000 -0700
@@ -0,0 +1,7 @@
+#ld: -shared
+#objdump: -dw
+#target: x86_64-*-* i?86-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt>
+#pass
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.s binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.s
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.s	1969-12-31 16:00:00.000000000 -0800
+++ binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.s	2009-05-24 19:11:29.000000000 -0700
@@ -0,0 +1,16 @@
+	.type foo, %gnu_indirect_function
+	.global __GI_foo
+	.hidden __GI_foo
+	.set __GI_foo, foo
+	.text
+.globl foo
+	.type	foo, @function
+foo:
+	ret
+	.size	foo, .-foo
+.globl bar
+	.type	bar, @function
+bar:
+	call	__GI_foo@PLT
+	ret
+	.size	bar, .-bar
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-2-i386.d binutils/ld/testsuite/ld-ifunc/ifunc-2-i386.d
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-2-i386.d	1969-12-31 16:00:00.000000000 -0800
+++ binutils/ld/testsuite/ld-ifunc/ifunc-2-i386.d	2009-05-29 12:47:29.000000000 -0700
@@ -0,0 +1,8 @@
+#ld: -m elf_i386 -shared
+#as: --32
+#objdump: -dw
+#target: x86_64-*-* i?86-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt>
+#pass
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-2-i386.s binutils/ld/testsuite/ld-ifunc/ifunc-2-i386.s
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-2-i386.s	1969-12-31 16:00:00.000000000 -0800
+++ binutils/ld/testsuite/ld-ifunc/ifunc-2-i386.s	2009-05-29 12:34:45.000000000 -0700
@@ -0,0 +1,21 @@
+	.type foo, %gnu_indirect_function
+	.global __GI_foo
+	.hidden __GI_foo
+	.set __GI_foo, foo
+	.text
+.globl foo
+	.type	foo, @function
+foo:
+	ret
+	.size	foo, .-foo
+.globl bar
+	.type	bar, @function
+bar:
+	call	.L6
+.L6:
+	popl	%ebx
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-.L6], %ebx
+	call	__GI_foo
+	leal	__GI_foo@GOTOFF(%ebx), %eax
+	ret
+	.size	bar, .-bar
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-2-x86-64.d binutils/ld/testsuite/ld-ifunc/ifunc-2-x86-64.d
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-2-x86-64.d	1969-12-31 16:00:00.000000000 -0800
+++ binutils/ld/testsuite/ld-ifunc/ifunc-2-x86-64.d	2009-05-29 12:41:07.000000000 -0700
@@ -0,0 +1,8 @@
+#ld: -shared
+#objdump: -dw
+#target: x86_64-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt>
+[ \t0-9a-f]+:[ \t0-9a-f]+lea[ \t]+.*\(%rip\),%rax.*[ \t0-9a-fq]+<\*ABS\*@plt>
+#pass
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-2-x86-64.s binutils/ld/testsuite/ld-ifunc/ifunc-2-x86-64.s
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-2-x86-64.s	1969-12-31 16:00:00.000000000 -0800
+++ binutils/ld/testsuite/ld-ifunc/ifunc-2-x86-64.s	2009-05-29 12:32:12.000000000 -0700
@@ -0,0 +1,17 @@
+	.type foo, %gnu_indirect_function
+	.global __GI_foo
+	.hidden __GI_foo
+	.set __GI_foo, foo
+	.text
+.globl foo
+	.type	foo, @function
+foo:
+	ret
+	.size	foo, .-foo
+.globl bar
+	.type	bar, @function
+bar:
+	call	__GI_foo
+	leaq	__GI_foo(%rip), %rax
+	ret
+	.size	bar, .-bar
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc.exp binutils/ld/testsuite/ld-ifunc/ifunc.exp
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc.exp	2009-05-23 14:39:29.000000000 -0700
+++ binutils/ld/testsuite/ld-ifunc/ifunc.exp	2009-05-27 15:25:45.000000000 -0700
@@ -98,6 +98,33 @@ proc contains_ifunc_symbol { binary_file
     return 1
 }
 
+# A procedure to confirm that a file contains the R_*_IRELATIVE
+# relocation.
+# Returns -1 upon error, 0 if the relocation was not found and 1 if
+# it was found.
+proc contains_irelative_reloc { binary_file } {
+    global READELF
+    global READELFFLAGS
+
+    catch "exec $READELF $READELFFLAGS --relocs --wide $binary_file > readelf.out" got
+
+    if ![string match "" $got] then {
+	verbose "proc contains_irelative_reloc: Readelf produced unexpected out processing $binary_file: $got"
+	return -1
+    }
+
+    # Look for a line like this:
+    #    0000000000600ab0  0000000000000025 R_X86_64_IRELATIVE      000000000040061c
+    #    080496f4  0000002a R_386_IRELATIVE
+
+
+    if { ![regexp "\[0-9a-f\]+\[ \]+\[0-9a-f\]+\[ \]+R_\[_0-9A-Z\]+_IRELATIVE\[ \]*\[0-9a-f\]*\n" [file_contents readelf.out]] } {
+	return 0
+    }
+
+    return 1
+}
+
 # A procedure to confirm that a file contains a relocation that references an IFUNC symbol.
 # Returns -1 upon error, 0 if the reloc was not found and 1 if it was found.
 proc contains_ifunc_reloc { binary_file } {
@@ -184,11 +211,16 @@ if { $fails == 0 } {
     return
 }
 
-# Check the executables.
+# Check the executables and shared libraries
 #
-# The linked ifunc using executables should have an OSABI field of LINUX
-# The linked non-ifunc using executable should have an OSABI field of NONE (aka System V).
+# The linked ifunc using executables and the shared library containing
+# ifunc should have an OSABI field of LINUX.  The linked non-ifunc using
+# executable should have an OSABI field of NONE (aka System V).
 
+if {! [check_osabi tmpdir/libshared_ifunc.so {UNIX - Linux}]} {
+    fail "Shared libraries containing ifunc does not have an OS/ABI field of LINUX"
+    set fails [expr $fails + 1]
+}
 if {! [check_osabi tmpdir/static_prog {UNIX - Linux}]} {
     fail "Static ifunc-using executable does not have an OS/ABI field of LINUX"
     set fails [expr $fails + 1]
@@ -202,9 +234,14 @@ if {! [check_osabi tmpdir/static_nonifun
     set fails [expr $fails + 1]
 }
 
-# The linked ifunc using executables should contain an IFUNC symbol,
-# The non-ifunc using executable should not.
+# The linked ifunc using executables and the shared library containing
+# ifunc should contain an IFUNC symbol.  The non-ifunc using executable
+# should not.
 
+if {[contains_ifunc_symbol tmpdir/libshared_ifunc.so] != 1} {
+    fail "Shared libraries containing ifunc does not contain an IFUNC symbol"
+    set fails [expr $fails + 1]
+}
 if {[contains_ifunc_symbol tmpdir/static_prog] != 1} {
     fail "Static ifunc-using executable does not contain an IFUNC symbol"
     set fails [expr $fails + 1]
@@ -218,12 +255,17 @@ if {[contains_ifunc_symbol tmpdir/static
     set fails [expr $fails + 1]
 }
 
-# The linked ifunc using executablea should contain a dynamic reloc referencing the IFUNC symbol.
-# (Even the static executable which should have a dynamic section created for it).
-# The non-ifunc using executable should not.
+# The linked ifunc using executables and shared libraries should contain
+# a dynamic reloc referencing the IFUNC symbol.  (Even the static
+# executable which should have a dynamic section created for it).  The
+# non-ifunc using executable should not.
 
-if {[contains_ifunc_reloc tmpdir/static_prog] != 1} {
-    fail "Static ifunc-using executable does not contain a reloc against an IFUNC symbol"
+if {[contains_irelative_reloc tmpdir/libshared_ifunc.so] != 1} {
+    fail "ifunc-using shared library does not contain R_*_IRELATIVE relocation"
+    set fails [expr $fails + 1]
+}
+if {[contains_irelative_reloc tmpdir/static_prog] != 1} {
+    fail "Static ifunc-using executable does not contain R_*_IRELATIVE relocation"
     set fails [expr $fails + 1]
 }
 if {[contains_ifunc_reloc tmpdir/dynamic_prog] != 1} {
@@ -252,3 +294,10 @@ if { $verbose < 1 } {
     remote_file host delete "tmpdir/static_prog"
     remote_file host delete "tmpdir/static_nonifunc_prog"
 }
+
+set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+foreach t $test_list {
+    # We need to strip the ".d", but can leave the dirname.
+    verbose [file rootname $t]
+    run_dump_test [file rootname $t]
+}
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/lib.c binutils/ld/testsuite/ld-ifunc/lib.c
--- ../binutils/src/ld/testsuite/ld-ifunc/lib.c	2009-04-30 08:47:12.000000000 -0700
+++ binutils/ld/testsuite/ld-ifunc/lib.c	2009-05-27 15:06:57.000000000 -0700
@@ -15,6 +15,19 @@ void * library_func2_ifunc (void) __asm_
 void * library_func2_ifunc (void) { return global ? minus_one : zero ; }
 __asm__(".type library_func2, %gnu_indirect_function");
 
+extern int library_func2 (int);
+extern __typeof (library_func2) library_func2 __asm__ ("__GI_library_func2");
+
+__asm__(".global __GI_library_func2");
+__asm__(".hidden __GI_library_func2");
+__asm__(".set __GI_library_func2, library_func2");
+
+int
+library_func (int x)
+{
+  return library_func2 (x);
+}
+
 #else /* WITHOUT_IFUNC */
 
 int


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