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]

PowerPC STT_GNU_IFUNC support


Preliminary STT_GNU_IFUNC support for PowerPC.  Not much use without
the glibc support, which I'll contribute after I get back from
vacation next week.

TODO:
- more testing
- merge with HJ's work, in particular use fields now in elf hash table.

include/elf/
	* ppc.h (R_PPC_IRELATIVE): Add.
	(R_PPC_RELAX32, R_PPC_RELAX32PC,
	R_PPC_RELAX32_PLT, R_PPC_RELAX32PC_PLT): Renumber.
	* ppc64.h (R_PPC64_IRELATIVE): Add.
bfd/
	* elf32-ppc.c (ppc_elf_howto_raw): Add R_PPC_IRELATIVE.
	(ppc_elf_get_synthetic_symtab): Report addend.
	(PLT_IFUNC): Define.
	(struct ppc_elf_link_hash_table): Add iplt and reliplt.
	(ppc_elf_create_glink): New function.
	(ppc_elf_create_dynamic_sections): Use it.
	(ppc_elf_add_symbol_hook): Set has_ifunc_symbols.
	(update_local_sym_info): Allocate space for local_plt array.
	Don't bump local_got_refcounts for PLT_IFUNC.  Return local_plt
	entry pointer.
	(is_branch_reloc): New function.
	(ppc_elf_check_relocs): Handle STT_GNU_IFUNC symbols.
	(ppc_elf_gc_sweep_hook): Likewise.
	(ppc_elf_adjust_dynamic_symbol): Likewise.
	(allocate_dynrelocs): Likewise.
	(ppc_elf_size_dynamic_sections): Likewise.
	(ppc_elf_relocate_section): Likewise.
	(branch_reloc_hash_match): Use is_branch_reloc.
	(ppc_elf_tls_optimize): Adjust for local_plt.
	(write_glink_stub): New function, extracted from..
	(ppc_elf_finish_dynamic_symbol): ..here.  Handle STT_GNU_IFUNC.
	(ppc_elf_finish_dynamic_sections): Only write plt resolver and
	branch table when dynamic.
	(elf_backend_post_process_headers): Define.
	* elf64-ppc.c (elf_backend_post_process_headers): Define.
	(ppc64_elf_howto_raw): Add R_PPC64_IRELATIVE.
	(ppc64_elf_get_synthetic_symtab): Report addend.
	(struct ppc_stub_hash_entry): Add plt_ent.
	(PLT_IFUNC): Define.
	(struct ppc_link_hash_table): Add iplt and reliplt.
	(create_linkage_sections): Make .iplt and .rela.iplt sections.
	(ppc64_elf_add_symbol_hook): Set has_ifunc_symbols.
	(update_local_sym_info): Allocate space for local_plt array.
	Don't bump local_got_ents for PLT_IFUNC.  Return local_plt
	entry pointer.
	(update_plt_info): Pass pointer to plt_entry rather than sym hash,
	and don't change hash flags here.
	(is_branch_reloc): New function.
	(ppc64_elf_check_relocs): Handle STT_GNU_IFUNC.
	(ppc64_elf_gc_sweep_hook): Likewise.
	(ppc64_elf_adjust_dynamic_symbol): Likewise.
	(allocate_dynrelocs): Likewise.
	(ppc64_elf_size_dynamic_sections): Likewise.
	(ppc_build_one_stub, ppc_size_one_stub): Likewise.
	(ppc64_elf_size_stubs): Likewise.
	(ppc64_elf_relocate_section): Likewise.
	(get_sym_h): Adjust for local_plt.
	(branch_reloc_hash_match): Use is_branch_reloc.
	(ppc_type_of_stub): Pass plt_entry pointer and handle ifunc.
	(ppc64_elf_toc): Ignore SEC_EXCLUDE sections.
ld/
	* emulparams/elf32ppc.sh (GOTPLT, PLT): Handle .iplt.
ld/testsuite/
	* ld-ifunc/ifunc.exp: Run for powerpc.  Really generate static
	executables, renaming the existing dynamic but local tests.

Index: include/elf/ppc.h
===================================================================
RCS file: /cvs/src/src/include/elf/ppc.h,v
retrieving revision 1.24
diff -u -p -r1.24 ppc.h
--- include/elf/ppc.h	22 Jun 2009 00:52:20 -0000	1.24
+++ include/elf/ppc.h	10 Jul 2009 08:09:10 -0000
@@ -71,6 +71,14 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
   RELOC_NUMBER (R_PPC_SECTOFF_HA,	 36)
   RELOC_NUMBER (R_PPC_ADDR30,		 37)
 
+#ifndef RELOC_MACROS_GEN_FUNC
+/* Fake relocations for branch stubs, only used internally by ld.  */
+  RELOC_NUMBER (R_PPC_RELAX32,		 48)
+  RELOC_NUMBER (R_PPC_RELAX32PC,	 49)
+  RELOC_NUMBER (R_PPC_RELAX32_PLT,	 50)
+  RELOC_NUMBER (R_PPC_RELAX32PC_PLT,	 51)
+#endif
+
   /* Relocs added to support TLS.  */
   RELOC_NUMBER (R_PPC_TLS,		 67)
   RELOC_NUMBER (R_PPC_DTPMOD32,		 68)
@@ -122,13 +130,8 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
   RELOC_NUMBER (R_PPC_EMB_BIT_FLD,	115)
   RELOC_NUMBER (R_PPC_EMB_RELSDA,	116)
 
-#ifndef RELOC_MACROS_GEN_FUNC
-/* Fake relocations for branch stubs, only used internally by ld.  */
-  RELOC_NUMBER (R_PPC_RELAX32,		245)
-  RELOC_NUMBER (R_PPC_RELAX32PC,	246)
-  RELOC_NUMBER (R_PPC_RELAX32_PLT,	247)
-  RELOC_NUMBER (R_PPC_RELAX32PC_PLT,	248)
-#endif
+/* Support STT_GNU_IFUNC plt calls.  */
+  RELOC_NUMBER (R_PPC_IRELATIVE,	248)
 
 /* These are GNU extensions used in PIC code sequences.  */
   RELOC_NUMBER (R_PPC_REL16,		249)
Index: include/elf/ppc64.h
===================================================================
RCS file: /cvs/src/src/include/elf/ppc64.h,v
retrieving revision 1.5
diff -u -p -r1.5 ppc64.h
--- include/elf/ppc64.h	4 Mar 2009 05:50:48 -0000	1.5
+++ include/elf/ppc64.h	10 Jul 2009 08:09:10 -0000
@@ -139,6 +139,9 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_typ
   RELOC_NUMBER (R_PPC64_TLSGD,		   107)
   RELOC_NUMBER (R_PPC64_TLSLD,		   108)
 
+/* Support STT_GNU_IFUNC plt calls.  */
+  RELOC_NUMBER (R_PPC64_IRELATIVE,	   248)
+
   /* These are GNU extensions to enable C++ vtable garbage collection.  */
   RELOC_NUMBER (R_PPC64_GNU_VTINHERIT,	   253)
   RELOC_NUMBER (R_PPC64_GNU_VTENTRY,	   254)
Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.259
diff -u -p -r1.259 elf32-ppc.c
--- bfd/elf32-ppc.c	22 Jun 2009 00:52:20 -0000	1.259
+++ bfd/elf32-ppc.c	10 Jul 2009 10:57:40 -0000
@@ -1382,6 +1382,20 @@ static reloc_howto_type ppc_elf_howto_ra
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
+  HOWTO (R_PPC_IRELATIVE,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	 /* special_function */
+	 "R_PPC_IRELATIVE",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
   /* A 16 bit relative relocation.  */
   HOWTO (R_PPC_REL16,		/* type */
 	 0,			/* rightshift */
@@ -2486,7 +2500,11 @@ ppc_elf_get_synthetic_symtab (bfd *abfd,
   size = count * sizeof (asymbol);
   p = relplt->relocation;
   for (i = 0; i < count; i++, p++)
-    size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+    {
+      size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+      if (p->addend != 0)
+	size += sizeof ("+0x") - 1 + 8;
+    }
 
   size += sizeof (asymbol) + sizeof ("__glink");
 
@@ -2516,6 +2534,13 @@ ppc_elf_get_synthetic_symtab (bfd *abfd,
       len = strlen ((*p->sym_ptr_ptr)->name);
       memcpy (names, (*p->sym_ptr_ptr)->name, len);
       names += len;
+      if (p->addend != 0)
+	{
+	  memcpy (names, "+0x", sizeof ("+0x") - 1);
+	  names += sizeof ("+0x") - 1;
+	  bfd_sprintf_vma (abfd, names, p->addend);
+	  names += strlen (names);
+	}
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
       ++s;
@@ -2665,6 +2690,7 @@ struct ppc_elf_link_hash_entry
 #define TLS_DTPREL	 8	/* DTPREL reloc, => LD. */
 #define TLS_TLS		16	/* Any TLS reloc.  */
 #define TLS_TPRELGD	32	/* TPREL reloc resulting from GD->IE. */
+#define PLT_IFUNC	64	/* STT_GNU_IFUNC.  */
   char tls_mask;
 
   /* Nonzero if we have seen a small data relocation referring to this
@@ -2686,6 +2712,8 @@ struct ppc_elf_link_hash_table
   asection *glink;
   asection *plt;
   asection *relplt;
+  asection *iplt;
+  asection *reliplt;
   asection *dynbss;
   asection *relbss;
   asection *dynsbss;
@@ -2852,6 +2880,38 @@ ppc_elf_create_got (bfd *abfd, struct bf
   return TRUE;
 }
 
+static bfd_boolean
+ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  asection *s;
+  flagword flags;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS
+	   | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags);
+  htab->glink = s;
+  if (s == NULL
+      || !bfd_set_section_alignment (abfd, s, 4))
+    return FALSE;
+
+  flags = SEC_ALLOC | SEC_LINKER_CREATED;
+  s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags);
+  htab->iplt = s;
+  if (s == NULL
+      || !bfd_set_section_alignment (abfd, s, 4))
+    return FALSE;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
+	   | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  s = bfd_make_section_with_flags (abfd, ".rela.iplt", flags);
+  htab->reliplt = s;
+  if (s == NULL
+      || ! bfd_set_section_alignment (abfd, s, 2))
+    return FALSE;
+  return TRUE;
+}
+
 /* We have to create .dynsbss and .rela.sbss here so that they get mapped
    to output sections (just like _bfd_elf_create_dynamic_sections has
    to create .dynbss and .rela.bss).  */
@@ -2872,13 +2932,8 @@ ppc_elf_create_dynamic_sections (bfd *ab
   if (!_bfd_elf_create_dynamic_sections (abfd, info))
     return FALSE;
 
-  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
-	   | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-
-  s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags | SEC_CODE);
-  htab->glink = s;
-  if (s == NULL
-      || !bfd_set_section_alignment (abfd, s, 4))
+  if (htab->glink == NULL
+      && !ppc_elf_create_glink (abfd, info))
     return FALSE;
 
   htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss");
@@ -2891,6 +2946,8 @@ ppc_elf_create_dynamic_sections (bfd *ab
   if (! info->shared)
     {
       htab->relbss = bfd_get_section_by_name (abfd, ".rela.bss");
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
+	       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
       s = bfd_make_section_with_flags (abfd, ".rela.sbss", flags);
       htab->relsbss = s;
       if (s == NULL
@@ -3064,6 +3121,9 @@ ppc_elf_add_symbol_hook (bfd *abfd,
       *valp = sym->st_size;
     }
 
+  if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+
   return TRUE;
 }
 
@@ -3212,30 +3272,35 @@ elf_create_pointer_linker_section (bfd *
   return TRUE;
 }
 
-static bfd_boolean
+static struct plt_entry **
 update_local_sym_info (bfd *abfd,
 		       Elf_Internal_Shdr *symtab_hdr,
 		       unsigned long r_symndx,
 		       int tls_type)
 {
   bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd);
+  struct plt_entry **local_plt;
   char *local_got_tls_masks;
 
   if (local_got_refcounts == NULL)
     {
       bfd_size_type size = symtab_hdr->sh_info;
 
-      size *= sizeof (*local_got_refcounts) + sizeof (*local_got_tls_masks);
+      size *= (sizeof (*local_got_refcounts)
+	       + sizeof (*local_plt)
+	       + sizeof (*local_got_tls_masks));
       local_got_refcounts = bfd_zalloc (abfd, size);
       if (local_got_refcounts == NULL)
-	return FALSE;
+	return NULL;
       elf_local_got_refcounts (abfd) = local_got_refcounts;
     }
 
-  local_got_refcounts[r_symndx] += 1;
-  local_got_tls_masks = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+  local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info);
+  local_got_tls_masks = (char *) (local_plt + symtab_hdr->sh_info);
   local_got_tls_masks[r_symndx] |= tls_type;
-  return TRUE;
+  if (tls_type != PLT_IFUNC)
+    local_got_refcounts[r_symndx] += 1;
+  return local_plt + r_symndx;
 }
 
 static bfd_boolean
@@ -3276,6 +3341,21 @@ find_plt_ent (struct plt_entry **plist, 
   return ent;
 }
 
+static bfd_boolean
+is_branch_reloc (enum elf_ppc_reloc_type r_type)
+{
+  return (r_type == R_PPC_PLTREL24
+	  || r_type == R_PPC_LOCAL24PC
+	  || r_type == R_PPC_REL24
+	  || r_type == R_PPC_REL14
+	  || r_type == R_PPC_REL14_BRTAKEN
+	  || r_type == R_PPC_REL14_BRNTAKEN
+	  || r_type == R_PPC_ADDR24
+	  || r_type == R_PPC_ADDR14
+	  || r_type == R_PPC_ADDR14_BRTAKEN
+	  || r_type == R_PPC_ADDR14_BRNTAKEN);
+}
+
 static void
 bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
 {
@@ -3342,6 +3422,7 @@ ppc_elf_check_relocs (bfd *abfd,
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
       int tls_type;
+      struct plt_entry **ifunc;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -3369,34 +3450,69 @@ ppc_elf_check_relocs (bfd *abfd,
 	}
 
       tls_type = 0;
+      ifunc = NULL;
       r_type = ELF32_R_TYPE (rel->r_info);
-      if (h != NULL && h == tga)
-	switch (r_type)
-	  {
-	  default:
-	    break;
+      if (!htab->is_vxworks && is_branch_reloc (r_type))
+	{
+	  if (h != NULL && h == tga)
+	    {
+	      if (rel != relocs
+		  && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
+		      || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
+		/* We have a new-style __tls_get_addr call with a marker
+		   reloc.  */
+		;
+	      else
+		/* Mark this section as having an old-style call.  */
+		sec->has_tls_get_addr_call = 1;
+	    }
 
-	  case R_PPC_PLTREL24:
-	  case R_PPC_LOCAL24PC:
-	  case R_PPC_REL24:
-	  case R_PPC_REL14:
-	  case R_PPC_REL14_BRTAKEN:
-	  case R_PPC_REL14_BRNTAKEN:
-	  case R_PPC_ADDR24:
-	  case R_PPC_ADDR14:
-	  case R_PPC_ADDR14_BRTAKEN:
-	  case R_PPC_ADDR14_BRNTAKEN:
-	    if (rel != relocs
-		&& (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
-		    || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
-	      /* We have a new-style __tls_get_addr call with a marker
-		 reloc.  */
-	      ;
-	    else
-	      /* Mark this section as having an old-style call.  */
-	      sec->has_tls_get_addr_call = 1;
-	    break;
-	  }
+	  /* STT_GNU_IFUNC symbols must have a PLT entry.  */
+	  if (h != NULL)
+	    {
+	      if (h->type == STT_GNU_IFUNC)
+		{
+		  h->needs_plt = 1;
+		  ifunc = &h->plt.plist;
+		}
+	    }
+	  else
+	    {
+	      Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+							      abfd, r_symndx);
+	      if (isym == NULL)
+		return FALSE;
+
+	      if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+		{
+		  ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+						 PLT_IFUNC);
+		  if (ifunc == NULL)
+		    return FALSE;
+		}
+	    }
+	  if (ifunc != NULL)
+	    {
+	      bfd_vma addend = 0;
+
+	      if (r_type == R_PPC_PLTREL24)
+		{
+		  ppc_elf_tdata (abfd)->makes_plt_call = 1;
+		  addend = rel->r_addend;
+		}
+	      if (!update_plt_info (abfd, ifunc,
+				    addend < 32768 ? NULL : got2, addend))
+		return FALSE;
+
+	      if (htab->glink == NULL)
+		{
+		  if (htab->elf.dynobj == NULL)
+		    htab->elf.dynobj = abfd;
+		  if (!ppc_elf_create_glink (htab->elf.dynobj, info))
+		    return FALSE;
+		}
+	    }
+	}
 
       switch (r_type)
 	{
@@ -3571,7 +3687,7 @@ ppc_elf_check_relocs (bfd *abfd,
 	  break;
 
 	case R_PPC_PLTREL24:
-	  if (h == NULL)
+	  if (h == NULL || ifunc != NULL)
 	    break;
 	  /* Fall through */
 	case R_PPC_PLT32:
@@ -3654,6 +3770,7 @@ ppc_elf_check_relocs (bfd *abfd,
 	case R_PPC_GLOB_DAT:
 	case R_PPC_JMP_SLOT:
 	case R_PPC_RELATIVE:
+	case R_PPC_IRELATIVE:
 	  break;
 
 	  /* These aren't handled yet.  We'll report an error later.  */
@@ -3782,7 +3899,9 @@ ppc_elf_check_relocs (bfd *abfd,
 	    {
 	      /* We may need a plt entry if the symbol turns out to be
 		 a function defined in a dynamic object.  */
-	      if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
+	      h->needs_plt = 1;
+	      if (ifunc == NULL
+		  && !update_plt_info (abfd, &h->plt.plist, NULL, 0))
 		return FALSE;
 	      break;
 	    }
@@ -4291,6 +4410,33 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
 	}
 
       r_type = ELF32_R_TYPE (rel->r_info);
+      if (!htab->is_vxworks && is_branch_reloc (r_type))
+	{
+	  struct plt_entry **ifunc = NULL;
+	  if (h != NULL)
+	    {
+	      if (h->type == STT_GNU_IFUNC)
+		ifunc = &h->plt.plist;
+	    }
+	  else if (local_got_refcounts != NULL)
+	    {
+	      struct plt_entry **local_plt = (struct plt_entry **)
+		(local_got_refcounts + symtab_hdr->sh_info);
+	      char *local_got_tls_masks = (char *)
+		(local_plt + symtab_hdr->sh_info);
+	      if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+		ifunc = local_plt + r_symndx;
+	    }
+	  if (ifunc != NULL)
+	    {
+	      bfd_vma addend = r_type == R_PPC_PLTREL24 ? rel->r_addend : 0;
+	      struct plt_entry *ent = find_plt_ent (ifunc, got2, addend);
+	      if (ent->plt.refcount > 0)
+		ent->plt.refcount -= 1;
+	      continue;
+	    }
+	}
+
       switch (r_type)
 	{
 	case R_PPC_GOT_TLSLD16:
@@ -4405,17 +4551,7 @@ branch_reloc_hash_match (const bfd *ibfd
   enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
   unsigned int r_symndx = ELF32_R_SYM (rel->r_info);
 
-  if (r_symndx >= symtab_hdr->sh_info
-      && (r_type == R_PPC_PLTREL24
-	  || r_type == R_PPC_LOCAL24PC
-	  || r_type == R_PPC_REL14
-	  || r_type == R_PPC_REL14_BRTAKEN
-	  || r_type == R_PPC_REL14_BRNTAKEN
-	  || r_type == R_PPC_REL24
-	  || r_type == R_PPC_ADDR24
-	  || r_type == R_PPC_ADDR14
-	  || r_type == R_PPC_ADDR14_BRTAKEN
-	  || r_type == R_PPC_ADDR14_BRNTAKEN))
+  if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type))
     {
       struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
       struct elf_link_hash_entry *h;
@@ -4580,6 +4716,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
 		    {
 		      Elf_Internal_Sym *sym;
 		      bfd_signed_vma *lgot_refs;
+		      struct plt_entry **local_plt;
 		      char *lgot_masks;
 
 		      if (locsyms == NULL)
@@ -4600,7 +4737,9 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
 		      lgot_refs = elf_local_got_refcounts (ibfd);
 		      if (lgot_refs == NULL)
 			abort ();
-		      lgot_masks = (char *) (lgot_refs + symtab_hdr->sh_info);
+		      local_plt = (struct plt_entry **)
+			(lgot_refs + symtab_hdr->sh_info);
+		      lgot_masks = (char *) (local_plt + symtab_hdr->sh_info);
 		      tls_mask = &lgot_masks[r_symndx];
 		      got_count = &lgot_refs[r_symndx];
 		    }
@@ -4690,6 +4829,7 @@ ppc_elf_adjust_dynamic_symbol (struct bf
 
   /* Deal with function syms.  */
   if (h->type == STT_FUNC
+      || h->type == STT_GNU_IFUNC
       || h->needs_plt)
     {
       /* Clear procedure linkage table information for any symbol that
@@ -4699,9 +4839,10 @@ ppc_elf_adjust_dynamic_symbol (struct bf
 	if (ent->plt.refcount > 0)
 	  break;
       if (ent == NULL
-	  || SYMBOL_CALLS_LOCAL (info, h)
-	  || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-	      && h->root.type == bfd_link_hash_undefweak))
+	  || (h->type != STT_GNU_IFUNC
+	      && (SYMBOL_CALLS_LOCAL (info, h)
+		  || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+		      && h->root.type == bfd_link_hash_undefweak))))
 	{
 	  /* A PLT entry is not required/allowed when:
 
@@ -4937,29 +5078,37 @@ allocate_dynrelocs (struct elf_link_hash
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
   htab = ppc_elf_hash_table (info);
-  if (htab->elf.dynamic_sections_created)
+  if (htab->elf.dynamic_sections_created
+      || h->type == STT_GNU_IFUNC)
     {
       struct plt_entry *ent;
       bfd_boolean doneone = FALSE;
       bfd_vma plt_offset = 0, glink_offset = 0;
+      bfd_boolean dyn;
 
       for (ent = h->plt.plist; ent != NULL; ent = ent->next)
 	if (ent->plt.refcount > 0)
 	  {
 	    /* Make sure this symbol is output as a dynamic symbol.  */
 	    if (h->dynindx == -1
-		&& !h->forced_local)
+		&& !h->forced_local
+		&& !h->def_regular
+		&& htab->elf.dynamic_sections_created)
 	      {
 		if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		  return FALSE;
 	      }
 
+	    dyn = htab->elf.dynamic_sections_created;
 	    if (info->shared
-		|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
+		|| h->type == STT_GNU_IFUNC
+		|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
 	      {
 		asection *s = htab->plt;
+		if (!dyn)
+		  s = htab->iplt;
 
-		if (htab->plt_type == PLT_NEW)
+		if (htab->plt_type == PLT_NEW || !dyn)
 		  {
 		    if (!doneone)
 		      {
@@ -5037,29 +5186,35 @@ allocate_dynrelocs (struct elf_link_hash
 		/* We also need to make an entry in the .rela.plt section.  */
 		if (!doneone)
 		  {
-		    htab->relplt->size += sizeof (Elf32_External_Rela);
-
-		    if (htab->plt_type == PLT_VXWORKS)
+		    if (!htab->elf.dynamic_sections_created)
+		      htab->reliplt->size += sizeof (Elf32_External_Rela);
+		    else
 		      {
-			/* Allocate space for the unloaded relocations.  */
-			if (!info->shared)
+			htab->relplt->size += sizeof (Elf32_External_Rela);
+
+			if (htab->plt_type == PLT_VXWORKS)
 			  {
-			    if (ent->plt.offset
-				== (bfd_vma) htab->plt_initial_entry_size)
+			    /* Allocate space for the unloaded relocations.  */
+			    if (!info->shared
+				&& htab->elf.dynamic_sections_created)
 			      {
+				if (ent->plt.offset
+				    == (bfd_vma) htab->plt_initial_entry_size)
+				  {
+				    htab->srelplt2->size
+				      += (sizeof (Elf32_External_Rela)
+					  * VXWORKS_PLTRESOLVE_RELOCS);
+				  }
+
 				htab->srelplt2->size
-				  += sizeof (Elf32_External_Rela)
-				      * VXWORKS_PLTRESOLVE_RELOCS;
+				  += (sizeof (Elf32_External_Rela)
+				      * VXWORKS_PLT_NON_JMP_SLOT_RELOCS);
 			      }
 
-			    htab->srelplt2->size
-			      += sizeof (Elf32_External_Rela)
-				  * VXWORKS_PLT_NON_JMP_SLOT_RELOCS;
+			    /* Every PLT entry has an associated GOT entry in
+			       .got.plt.  */
+			    htab->sgotplt->size += 4;
 			  }
-
-			/* Every PLT entry has an associated GOT entry in
-			   .got.plt.  */
-			htab->sgotplt->size += 4;
 		      }
 		    doneone = TRUE;
 		  }
@@ -5091,6 +5246,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.  */
       if (eh->elf.dynindx == -1
 	  && !eh->elf.forced_local
+	  && !eh->elf.def_regular
 	  && htab->elf.dynamic_sections_created)
 	{
 	  if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
@@ -5206,7 +5362,8 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure undefined weak symbols are output as a dynamic
 	     symbol in PIEs.  */
 	  else if (h->dynindx == -1
-		   && !h->forced_local)
+		   && !h->forced_local
+		   && !h->def_regular)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
@@ -5225,7 +5382,8 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && !h->forced_local
+	      && !h->def_regular)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
@@ -5315,6 +5473,8 @@ ppc_elf_size_dynamic_sections (bfd *outp
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
+      struct plt_entry **local_plt;
+      struct plt_entry **end_local_plt;
       char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
@@ -5365,7 +5525,9 @@ ppc_elf_size_dynamic_sections (bfd *outp
       symtab_hdr = &elf_symtab_hdr (ibfd);
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
-      lgot_masks = (char *) end_local_got;
+      local_plt = (struct plt_entry **) end_local_got;
+      end_local_plt = local_plt + locsymcount;
+      lgot_masks = (char *) end_local_plt;
       for (; local_got < end_local_got; ++local_got, ++lgot_masks)
 	if (*local_got > 0)
 	  {
@@ -5395,6 +5557,46 @@ ppc_elf_size_dynamic_sections (bfd *outp
 	  }
 	else
 	  *local_got = (bfd_vma) -1;
+
+      if (htab->is_vxworks)
+	continue;
+
+      /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
+      for (; local_plt < end_local_plt; ++local_plt)
+	{
+	  struct plt_entry *ent;
+	  bfd_boolean doneone = FALSE;
+	  bfd_vma plt_offset = 0, glink_offset = 0;
+
+	  for (ent = *local_plt; ent != NULL; ent = ent->next)
+	    if (ent->plt.refcount > 0)
+	      {
+		asection *s = htab->iplt;
+
+		if (!doneone)
+		  {
+		    plt_offset = s->size;
+		    s->size += 4;
+		  }
+		ent->plt.offset = plt_offset;
+
+		s = htab->glink;
+		if (!doneone || info->shared || info->pie)
+		  {
+		    glink_offset = s->size;
+		    s->size += GLINK_ENTRY_SIZE;
+		  }
+		ent->glink_offset = glink_offset;
+
+		if (!doneone)
+		  {
+		    htab->reliplt += sizeof (Elf32_External_Rela);
+		    doneone = TRUE;
+		  }
+	      }
+	    else
+	      ent->plt.offset = (bfd_vma) -1;
+	}
     }
 
   /* Allocate space for global sym dynamic relocs.  */
@@ -5428,7 +5630,9 @@ ppc_elf_size_dynamic_sections (bfd *outp
       htab->elf.hgot->root.u.def.value = g_o_t;
     }
 
-  if (htab->glink != NULL && htab->glink->size != 0)
+  if (htab->glink != NULL
+      && htab->glink->size != 0
+      && htab->elf.dynamic_sections_created)
     {
       htab->glink_pltresolve = htab->glink->size;
       /* Space for the branch table.  */
@@ -5484,22 +5688,23 @@ ppc_elf_size_dynamic_sections (bfd *outp
 	continue;
 
       if (s == htab->plt
-	  || s == htab->glink
-	  || s == htab->got
-	  || s == htab->sgotplt
-	  || s == htab->sbss
-	  || s == htab->dynbss
-	  || s == htab->dynsbss)
+	  || s == htab->got)
 	{
 	  /* We'd like to strip these sections if they aren't needed, but if
 	     we've exported dynamic symbols from them we must leave them.
 	     It's too late to tell BFD to get rid of the symbols.  */
-	  if ((s == htab->plt || s == htab->got) && htab->elf.hplt != NULL)
+	  if (htab->elf.hplt != NULL)
 	    strip_section = FALSE;
 	  /* Strip this section if we don't need it; see the
 	     comment below.  */
 	}
-      else if (s == htab->sdata[0].section
+      else if (s == htab->iplt
+	       || s == htab->glink
+	       || s == htab->sgotplt
+	       || s == htab->sbss
+	       || s == htab->dynbss
+	       || s == htab->dynsbss
+	       || s == htab->sdata[0].section
 	       || s == htab->sdata[1].section)
 	{
 	  /* Strip these too.  */
@@ -6192,6 +6397,73 @@ elf_finish_pointer_linker_section (bfd *
   return relocation - linker_section_ptr->addend;
 }
 
+#define PPC_LO(v) ((v) & 0xffff)
+#define PPC_HI(v) (((v) >> 16) & 0xffff)
+#define PPC_HA(v) PPC_HI ((v) + 0x8000)
+
+static void
+write_glink_stub (struct plt_entry *ent, asection *plt_sec,
+		  struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  bfd *output_bfd = info->output_bfd;
+  bfd_vma plt;
+  unsigned char *p;
+
+  plt = ((ent->plt.offset & ~1)
+	 + plt_sec->output_section->vma
+	 + plt_sec->output_offset);
+  p = (unsigned char *) htab->glink->contents + ent->glink_offset;
+
+  if (info->shared || info->pie)
+    {
+      bfd_vma got = 0;
+
+      if (ent->addend >= 32768)
+	got = (ent->addend
+	       + ent->sec->output_section->vma
+	       + ent->sec->output_offset);
+      else if (htab->elf.hgot != NULL)
+	got = SYM_VAL (htab->elf.hgot);
+
+      plt -= got;
+
+      if (plt + 0x8000 < 0x10000)
+	{
+	  bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p);
+	  p += 4;
+	  bfd_put_32 (output_bfd, MTCTR_11, p);
+	  p += 4;
+	  bfd_put_32 (output_bfd, BCTR, p);
+	  p += 4;
+	  bfd_put_32 (output_bfd, NOP, p);
+	  p += 4;
+	}
+      else
+	{
+	  bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p);
+	  p += 4;
+	  bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
+	  p += 4;
+	  bfd_put_32 (output_bfd, MTCTR_11, p);
+	  p += 4;
+	  bfd_put_32 (output_bfd, BCTR, p);
+	  p += 4;
+	}
+    }
+  else
+    {
+      bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p);
+      p += 4;
+      bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
+      p += 4;
+      bfd_put_32 (output_bfd, MTCTR_11, p);
+      p += 4;
+      bfd_put_32 (output_bfd, BCTR, p);
+      p += 4;
+    }
+}
+
 /* The RELOCATE_SECTION function is called by the ELF backend linker
    to handle the relocations for a section.
 
@@ -6285,6 +6557,7 @@ ppc_elf_relocate_section (bfd *output_bf
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
       unsigned int tls_type, tls_mask, tls_gd;
+      struct plt_entry **ifunc;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       sym = NULL;
@@ -6349,8 +6622,11 @@ ppc_elf_relocate_section (bfd *output_bf
 	tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
       else if (local_got_offsets != NULL)
 	{
+	  struct plt_entry **local_plt;
 	  char *lgot_masks;
-	  lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
+	  local_plt
+	    = (struct plt_entry **) (local_got_offsets + symtab_hdr->sh_info);
+	  lgot_masks = (char *) (local_plt + symtab_hdr->sh_info);
 	  tls_mask = lgot_masks[r_symndx];
 	}
 
@@ -6371,7 +6647,7 @@ ppc_elf_relocate_section (bfd *output_bf
 
 	case R_PPC_GOT_TPREL16:
 	case R_PPC_GOT_TPREL16_LO:
-	  if (tls_mask != 0
+	  if ((tls_mask & TLS_TLS) != 0
 	      && (tls_mask & TLS_TPREL) == 0)
 	    {
 	      bfd_vma insn;
@@ -6385,7 +6661,7 @@ ppc_elf_relocate_section (bfd *output_bf
 	  break;
 
 	case R_PPC_TLS:
-	  if (tls_mask != 0
+	  if ((tls_mask & TLS_TLS) != 0
 	      && (tls_mask & TLS_TPREL) == 0)
 	    {
 	      bfd_vma insn, rtra;
@@ -6432,13 +6708,13 @@ ppc_elf_relocate_section (bfd *output_bf
 	case R_PPC_GOT_TLSGD16_HI:
 	case R_PPC_GOT_TLSGD16_HA:
 	  tls_gd = TLS_TPRELGD;
-	  if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+	  if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
 	    goto tls_gdld_hi;
 	  break;
 
 	case R_PPC_GOT_TLSLD16_HI:
 	case R_PPC_GOT_TLSLD16_HA:
-	  if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+	  if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
 	    {
 	    tls_gdld_hi:
 	      if ((tls_mask & tls_gd) != 0)
@@ -6457,13 +6733,13 @@ ppc_elf_relocate_section (bfd *output_bf
 	case R_PPC_GOT_TLSGD16:
 	case R_PPC_GOT_TLSGD16_LO:
 	  tls_gd = TLS_TPRELGD;
-	  if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+	  if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
 	    goto tls_ldgd_opt;
 	  break;
 
 	case R_PPC_GOT_TLSLD16:
 	case R_PPC_GOT_TLSLD16_LO:
-	  if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+	  if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
 	    {
 	      unsigned int insn1, insn2;
 	      bfd_vma offset;
@@ -6543,7 +6819,7 @@ ppc_elf_relocate_section (bfd *output_bf
 	  break;
 
 	case R_PPC_TLSGD:
-	  if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+	  if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
 	    {
 	      unsigned int insn2;
 	      bfd_vma offset = rel->r_offset;
@@ -6571,7 +6847,7 @@ ppc_elf_relocate_section (bfd *output_bf
 	  break;
 
 	case R_PPC_TLSLD:
-	  if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+	  if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
 	    {
 	      unsigned int insn2;
 
@@ -6635,6 +6911,64 @@ ppc_elf_relocate_section (bfd *output_bf
 	  break;
 	}
 
+      ifunc = NULL;
+      if (!htab->is_vxworks && is_branch_reloc (r_type))
+	{
+	  if (h != NULL)
+	    {
+	      if (h->type == STT_GNU_IFUNC)
+		ifunc = &h->plt.plist;
+	    }
+	  else if (local_got_offsets != NULL)
+	    {
+	      if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+		{
+		  struct plt_entry **local_plt = (struct plt_entry **)
+		    (local_got_offsets + symtab_hdr->sh_info);
+
+		  ifunc = local_plt + r_symndx;
+		}
+	    }
+	  if (ifunc != NULL)
+	    {
+	      struct plt_entry *ent = find_plt_ent (ifunc, got2, rel->r_addend);
+
+	      if (h == NULL && (ent->plt.offset & 1) == 0)
+		{
+		  Elf_Internal_Rela rela;
+		  bfd_byte *loc;
+
+		  rela.r_offset = (htab->iplt->output_section->vma
+				   + htab->iplt->output_offset
+				   + ent->plt.offset);
+		  rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+		  rela.r_addend = relocation;
+		  loc = (htab->reliplt->contents
+			 + ent->plt.offset * sizeof (Elf32_External_Rela) / 4);
+		  bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+
+		  ent->plt.offset |= 1;
+		}
+	      if (h == NULL && (ent->glink_offset & 1) == 0)
+		{
+		  write_glink_stub (ent, htab->iplt, info);
+		  ent->glink_offset |= 1;
+		}
+
+	      unresolved_reloc = FALSE;
+	      if (htab->plt_type == PLT_NEW
+		  || !htab->elf.dynamic_sections_created
+		  || h == NULL)
+		relocation = (htab->glink->output_section->vma
+			      + htab->glink->output_offset
+			      + (ent->glink_offset & ~1));
+	      else
+		relocation = (htab->plt->output_section->vma
+			      + htab->plt->output_offset
+			      + ent->plt.offset);
+	    }
+	}
+
       addend = rel->r_addend;
       tls_type = 0;
       howto = NULL;
@@ -7217,7 +7551,7 @@ ppc_elf_relocate_section (bfd *output_bf
 	  break;
 
 	case R_PPC_PLTREL24:
-	  if (h == NULL)
+	  if (h == NULL || ifunc != NULL)
 	    break;
 	  /* Relocation is to the entry for this symbol in the
 	     procedure linkage table.  */
@@ -7389,6 +7723,7 @@ ppc_elf_relocate_section (bfd *output_bf
 	case R_PPC_GLOB_DAT:
 	case R_PPC_JMP_SLOT:
 	case R_PPC_RELATIVE:
+	case R_PPC_IRELATIVE:
 	case R_PPC_PLT32:
 	case R_PPC_PLTREL32:
 	case R_PPC_PLT16_LO:
@@ -7524,10 +7859,6 @@ ppc_elf_relocate_section (bfd *output_bf
   return ret;
 }
 
-#define PPC_LO(v) ((v) & 0xffff)
-#define PPC_HI(v) (((v) >> 16) & 0xffff)
-#define PPC_HA(v) PPC_HI ((v) + 0x8000)
-
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
 
@@ -7559,7 +7890,8 @@ ppc_elf_finish_dynamic_symbol (bfd *outp
 	    bfd_byte *loc;
 	    bfd_vma reloc_index;
 
-	    if (htab->plt_type == PLT_NEW)
+	    if (htab->plt_type == PLT_NEW
+		|| !htab->elf.dynamic_sections_created)
 	      reloc_index = ent->plt.offset / 4;
 	    else
 	      {
@@ -7572,7 +7904,8 @@ ppc_elf_finish_dynamic_symbol (bfd *outp
 
 	    /* This symbol has an entry in the procedure linkage table.
 	       Set it up.  */
-	    if (htab->plt_type == PLT_VXWORKS)
+	    if (htab->plt_type == PLT_VXWORKS
+		&& htab->elf.dynamic_sections_created)
 	      {
 		bfd_vma got_offset;
 		const bfd_vma *plt_entry;
@@ -7694,10 +8027,15 @@ ppc_elf_finish_dynamic_symbol (bfd *outp
 	      }
 	    else
 	      {
-		rela.r_offset = (htab->plt->output_section->vma
-				 + htab->plt->output_offset
+		asection *splt = htab->plt;
+		if (!htab->elf.dynamic_sections_created)
+		  splt = htab->iplt;
+
+		rela.r_offset = (splt->output_section->vma
+				 + splt->output_offset
 				 + ent->plt.offset);
-		if (htab->plt_type == PLT_OLD)
+		if (htab->plt_type == PLT_OLD
+		    || !htab->elf.dynamic_sections_created)
 		  {
 		    /* We don't need to fill in the .plt.  The ppc dynamic
 		       linker will fill it in.  */
@@ -7708,16 +8046,30 @@ ppc_elf_finish_dynamic_symbol (bfd *outp
 				   + htab->glink->output_section->vma
 				   + htab->glink->output_offset);
 		    bfd_put_32 (output_bfd, val,
-				htab->plt->contents + ent->plt.offset);
+				splt->contents + ent->plt.offset);
 		  }
 	      }
 
 	    /* Fill in the entry in the .rela.plt section.  */
-	    rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
 	    rela.r_addend = 0;
+	    if (!htab->elf.dynamic_sections_created
+		|| h->dynindx == -1)
+	      {
+		BFD_ASSERT (h->type == STT_GNU_IFUNC
+			    && h->def_regular
+			    && (h->root.type == bfd_link_hash_defined
+				|| h->root.type == bfd_link_hash_defweak));
+		rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+		rela.r_addend = SYM_VAL (h);
+	      }
+	    else
+	      rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
 
-	    loc = (htab->relplt->contents
-		   + reloc_index * sizeof (Elf32_External_Rela));
+	    if (!htab->elf.dynamic_sections_created)
+	      loc = htab->reliplt->contents;
+	    else
+	      loc = htab->relplt->contents;
+	    loc += reloc_index * sizeof (Elf32_External_Rela);
 	    bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
 	    if (!h->def_regular)
@@ -7743,66 +8095,18 @@ ppc_elf_finish_dynamic_symbol (bfd *outp
 	    doneone = TRUE;
 	  }
 
-	if (htab->plt_type == PLT_NEW)
+	if (htab->plt_type == PLT_NEW
+	    || !htab->elf.dynamic_sections_created)
 	  {
-	    bfd_vma plt;
-	    unsigned char *p;
-
-	    plt = (ent->plt.offset
-		   + htab->plt->output_section->vma
-		   + htab->plt->output_offset);
-	    p = (unsigned char *) htab->glink->contents + ent->glink_offset;
+	    asection *splt = htab->plt;
+	    if (!htab->elf.dynamic_sections_created)
+	      splt = htab->iplt;
 
-	    if (info->shared || info->pie)
-	      {
-		bfd_vma got = 0;
+	    write_glink_stub (ent, splt, info);
 
-		if (ent->addend >= 32768)
-		  got = (ent->addend
-			 + ent->sec->output_section->vma
-			 + ent->sec->output_offset);
-		else if (htab->elf.hgot != NULL)
-		  got = SYM_VAL (htab->elf.hgot);
-
-		plt -= got;
-
-		if (plt + 0x8000 < 0x10000)
-		  {
-		    bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p);
-		    p += 4;
-		    bfd_put_32 (output_bfd, MTCTR_11, p);
-		    p += 4;
-		    bfd_put_32 (output_bfd, BCTR, p);
-		    p += 4;
-		    bfd_put_32 (output_bfd, NOP, p);
-		    p += 4;
-		  }
-		else
-		  {
-		    bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p);
-		    p += 4;
-		    bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
-		    p += 4;
-		    bfd_put_32 (output_bfd, MTCTR_11, p);
-		    p += 4;
-		    bfd_put_32 (output_bfd, BCTR, p);
-		    p += 4;
-		  }
-	      }
-	    else
-	      {
-		bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p);
-		p += 4;
-		bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
-		p += 4;
-		bfd_put_32 (output_bfd, MTCTR_11, p);
-		p += 4;
-		bfd_put_32 (output_bfd, BCTR, p);
-		p += 4;
-
-		/* We only need one non-PIC glink stub.  */
-		break;
-	      }
+	    if (!info->shared && !info->pie)
+	      /* We only need one non-PIC glink stub.  */
+	      break;
 	  }
 	else
 	  break;
@@ -8073,7 +8377,9 @@ ppc_elf_finish_dynamic_sections (bfd *ou
 	}
     }
 
-  if (htab->glink != NULL && htab->glink->contents != NULL)
+  if (htab->glink != NULL
+      && htab->glink->contents != NULL
+      && htab->elf.dynamic_sections_created)
     {
       unsigned char *p;
       unsigned char *endp;
@@ -8340,6 +8646,7 @@ ppc_elf_finish_dynamic_sections (bfd *ou
 #define elf_backend_plt_sym_val			ppc_elf_plt_sym_val
 #define elf_backend_action_discarded		ppc_elf_action_discarded
 #define elf_backend_init_index_section		_bfd_elf_init_1_index_section
+#define elf_backend_post_process_headers	_bfd_elf_set_osabi
 
 #include "elf32-target.h"
 
@@ -8449,5 +8756,6 @@ ppc_elf_vxworks_final_write_processing (
 
 #undef elf32_bed
 #define elf32_bed				ppc_elf_vxworks_bed
+#undef elf_backend_post_process_headers
 
 #include "elf32-target.h"
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.297
diff -u -p -r1.297 elf64-ppc.c
--- bfd/elf64-ppc.c	22 Jun 2009 00:00:32 -0000	1.297
+++ bfd/elf64-ppc.c	10 Jul 2009 10:57:46 -0000
@@ -112,6 +112,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_finish_dynamic_sections   ppc64_elf_finish_dynamic_sections
 #define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
 #define elf_backend_special_sections	      ppc64_elf_special_sections
+#define elf_backend_post_process_headers      _bfd_elf_set_osabi
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -1873,6 +1874,20 @@ static reloc_howto_type ppc64_elf_howto_
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
+  HOWTO (R_PPC64_IRELATIVE,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size (0=byte, 1=short, 2=long, 4=64 bits) */
+	 64,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_PPC64_IRELATIVE",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 ONES (64),		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC64_GNU_VTINHERIT,	/* type */
 	 0,			/* rightshift */
@@ -3116,7 +3131,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
 
 	      p = relplt->relocation;
 	      for (i = 0; i < plt_count; i++, p++)
-		size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+		{
+		  size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+		  if (p->addend != 0)
+		    size += sizeof ("+0x") - 1 + 16;
+		}
 	    }
 	}
 
@@ -3236,6 +3255,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
 	      len = strlen ((*p->sym_ptr_ptr)->name);
 	      memcpy (names, (*p->sym_ptr_ptr)->name, len);
 	      names += len;
+	      if (p->addend != 0)
+		{
+		  memcpy (names, "+0x", sizeof ("+0x") - 1);
+		  names += sizeof ("+0x") - 1;
+		  bfd_sprintf_vma (abfd, names, p->addend);
+		  names += strlen (names);
+		}
 	      memcpy (names, "@plt", sizeof ("@plt"));
 	      names += sizeof ("@plt");
 	      s++;
@@ -3518,6 +3544,7 @@ struct ppc_stub_hash_entry {
 
   /* The symbol table entry, if any, that this was derived from.  */
   struct ppc_link_hash_entry *h;
+  struct plt_entry *plt_ent;
 
   /* And the reloc addend that this was derived from.  */
   bfd_vma addend;
@@ -3586,6 +3613,7 @@ struct ppc_link_hash_entry
 #define TLS_TLS		16	/* Any TLS reloc.  */
 #define TLS_EXPLICIT	32	/* Marks TOC section TLS relocs. */
 #define TLS_TPRELGD	64	/* TPREL reloc resulting from GD->IE. */
+#define PLT_IFUNC      128	/* STT_GNU_IFUNC.  */
   char tls_mask;
 };
 
@@ -3638,6 +3666,8 @@ struct ppc_link_hash_table
   asection *got;
   asection *plt;
   asection *relplt;
+  asection *iplt;
+  asection *reliplt;
   asection *dynbss;
   asection *relbss;
   asection *glink;
@@ -4062,6 +4092,21 @@ create_linkage_sections (bfd *dynobj, st
       || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
     return FALSE;
 
+  flags = SEC_ALLOC | SEC_LINKER_CREATED;
+  htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
+  if (htab->iplt == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->iplt, 3))
+    return FALSE;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+	   | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->reliplt = bfd_make_section_anyway_with_flags (dynobj,
+						      ".rela.iplt",
+						      flags);
+  if (htab->reliplt == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3))
+    return FALSE;
+
   /* Create branch lookup table for plt_branch stubs.  */
   flags = (SEC_ALLOC | SEC_LOAD
 	   | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
@@ -4079,7 +4124,7 @@ create_linkage_sections (bfd *dynobj, st
   htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
 						      ".rela.branch_lt",
 						      flags);
-  if (!htab->relbrlt
+  if (htab->relbrlt == NULL
       || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
     return FALSE;
 
@@ -4367,15 +4412,19 @@ make_fdh (struct bfd_link_info *info,
 
 static bfd_boolean
 ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
-			   struct bfd_link_info *info ATTRIBUTE_UNUSED,
+			   struct bfd_link_info *info,
 			   Elf_Internal_Sym *isym,
 			   const char **name ATTRIBUTE_UNUSED,
 			   flagword *flags ATTRIBUTE_UNUSED,
 			   asection **sec,
 			   bfd_vma *value ATTRIBUTE_UNUSED)
 {
-  if (*sec != NULL
-      && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
+  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+  else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
+    ;
+  else if (*sec != NULL
+	   && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
     isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
 
   return TRUE;
@@ -4533,25 +4582,28 @@ ppc64_elf_as_needed_cleanup (bfd *ibfd A
   return TRUE;
 }
 
-static bfd_boolean
+static struct plt_entry **
 update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
 		       unsigned long r_symndx, bfd_vma r_addend, int tls_type)
 {
   struct got_entry **local_got_ents = elf_local_got_ents (abfd);
+  struct plt_entry **local_plt;
   char *local_got_tls_masks;
 
   if (local_got_ents == NULL)
     {
       bfd_size_type size = symtab_hdr->sh_info;
 
-      size *= sizeof (*local_got_ents) + sizeof (*local_got_tls_masks);
+      size *= (sizeof (*local_got_ents)
+	       + sizeof (*local_plt)
+	       + sizeof (*local_got_tls_masks));
       local_got_ents = bfd_zalloc (abfd, size);
       if (local_got_ents == NULL)
-	return FALSE;
+	return NULL;
       elf_local_got_ents (abfd) = local_got_ents;
     }
 
-  if ((tls_type & TLS_EXPLICIT) == 0)
+  if ((tls_type & (PLT_IFUNC | TLS_EXPLICIT)) == 0)
     {
       struct got_entry *ent;
 
@@ -4576,17 +4628,19 @@ update_local_sym_info (bfd *abfd, Elf_In
       ent->got.refcount += 1;
     }
 
-  local_got_tls_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
+  local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info);
+  local_got_tls_masks = (char *) (local_plt + symtab_hdr->sh_info);
   local_got_tls_masks[r_symndx] |= tls_type;
-  return TRUE;
+
+  return local_plt + r_symndx;
 }
 
 static bfd_boolean
-update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
+update_plt_info (bfd *abfd, struct plt_entry **plist, bfd_vma addend)
 {
   struct plt_entry *ent;
 
-  for (ent = eh->elf.plt.plist; ent != NULL; ent = ent->next)
+  for (ent = *plist; ent != NULL; ent = ent->next)
     if (ent->addend == addend)
       break;
   if (ent == NULL)
@@ -4595,19 +4649,28 @@ update_plt_info (bfd *abfd, struct ppc_l
       ent = bfd_alloc (abfd, amt);
       if (ent == NULL)
 	return FALSE;
-      ent->next = eh->elf.plt.plist;
+      ent->next = *plist;
       ent->addend = addend;
       ent->plt.refcount = 0;
-      eh->elf.plt.plist = ent;
+      *plist = ent;
     }
   ent->plt.refcount += 1;
-  eh->elf.needs_plt = 1;
-  if (eh->elf.root.root.string[0] == '.'
-      && eh->elf.root.root.string[1] != '\0')
-    eh->is_func = 1;
   return TRUE;
 }
 
+static bfd_boolean
+is_branch_reloc (enum elf_ppc64_reloc_type r_type)
+{
+  return (r_type == R_PPC64_REL24
+	  || r_type == R_PPC64_REL14
+	  || r_type == R_PPC64_REL14_BRTAKEN
+	  || r_type == R_PPC64_REL14_BRNTAKEN
+	  || r_type == R_PPC64_ADDR24
+	  || r_type == R_PPC64_ADDR14
+	  || r_type == R_PPC64_ADDR14_BRTAKEN
+	  || r_type == R_PPC64_ADDR14_BRNTAKEN);
+}
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
@@ -4685,6 +4748,7 @@ ppc64_elf_check_relocs (bfd *abfd, struc
       enum elf_ppc64_reloc_type r_type;
       int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
+      struct plt_entry **ifunc;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -4698,32 +4762,51 @@ ppc64_elf_check_relocs (bfd *abfd, struc
 	}
 
       tls_type = 0;
+      ifunc = NULL;
       r_type = ELF64_R_TYPE (rel->r_info);
-      if (h != NULL && (h == tga || h == dottga))
-	switch (r_type)
-	  {
-	  default:
-	    break;
+      if (is_branch_reloc (r_type))
+	{
+	  if (h != NULL && (h == tga || h == dottga))
+	    {
+	      if (rel != relocs
+		  && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+		      || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+		/* We have a new-style __tls_get_addr call with a marker
+		   reloc.  */
+		;
+	      else
+		/* Mark this section as having an old-style call.  */
+		sec->has_tls_get_addr_call = 1;
+	    }
 
-	  case R_PPC64_REL24:
-	  case R_PPC64_REL14:
-	  case R_PPC64_REL14_BRTAKEN:
-	  case R_PPC64_REL14_BRNTAKEN:
-	  case R_PPC64_ADDR24:
-	  case R_PPC64_ADDR14:
-	  case R_PPC64_ADDR14_BRTAKEN:
-	  case R_PPC64_ADDR14_BRNTAKEN:
-	    if (rel != relocs
-		&& (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
-		    || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
-	      /* We have a new-style __tls_get_addr call with a marker
-		 reloc.  */
-	      ;
-	    else
-	      /* Mark this section as having an old-style call.  */
-	      sec->has_tls_get_addr_call = 1;
-	    break;
-	  }
+	  /* STT_GNU_IFUNC symbols must have a PLT entry.  */
+	  if (h != NULL)
+	    {
+	      if (h->type == STT_GNU_IFUNC)
+		{
+		  h->needs_plt = 1;
+		  ifunc = &h->plt.plist;
+		}
+	    }
+	  else
+	    {
+	      Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+							      abfd, r_symndx);
+	      if (isym == NULL)
+		return FALSE;
+
+	      if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+		{
+		  ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+						 rel->r_addend, PLT_IFUNC);
+		  if (ifunc == NULL)
+		    return FALSE;
+		}
+	    }
+	  if (ifunc != NULL
+	      && !update_plt_info (abfd, ifunc, rel->r_addend))
+	    return FALSE;
+	}
 
       switch (r_type)
 	{
@@ -4829,9 +4912,14 @@ ppc64_elf_check_relocs (bfd *abfd, struc
 	      return FALSE;
 	    }
 	  else
-	    if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
-				  rel->r_addend))
-	      return FALSE;
+	    {
+	      if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
+		return FALSE;
+	      h->needs_plt = 1;
+	      if (h->root.root.string[0] == '.'
+		  && h->root.root.string[1] != '\0')
+		((struct ppc_link_hash_entry *) h)->is_func = 1;
+	    }
 	  break;
 
 	  /* The following relocations don't need to propagate the
@@ -4914,13 +5002,16 @@ ppc64_elf_check_relocs (bfd *abfd, struc
 	  /* Fall through.  */
 
 	case R_PPC64_REL24:
-	  if (h != NULL)
+	  if (h != NULL && ifunc == NULL)
 	    {
 	      /* We may need a .plt entry if the function this reloc
 		 refers to is in a shared lib.  */
-	      if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
-				    rel->r_addend))
+	      if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
 		return FALSE;
+	      h->needs_plt = 1;
+	      if (h->root.root.string[0] == '.'
+		  && h->root.root.string[1] != '\0')
+		((struct ppc_link_hash_entry *) h)->is_func = 1;
 	      if (h == tga || h == dottga)
 		sec->has_tls_reloc = 1;
 	    }
@@ -5525,6 +5616,38 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, stru
 	      }
 	}
 
+      if (is_branch_reloc (r_type))
+	{
+	  struct plt_entry **ifunc = NULL;
+	  if (h != NULL)
+	    {
+	      if (h->type == STT_GNU_IFUNC)
+		ifunc = &h->plt.plist;
+	    }
+	  else if (local_got_ents != NULL)
+	    {
+	      struct plt_entry **local_plt = (struct plt_entry **)
+		(local_got_ents + symtab_hdr->sh_info);
+	      char *local_got_tls_masks = (char *)
+		(local_plt + symtab_hdr->sh_info);
+	      if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+		ifunc = local_plt + r_symndx;
+	    }
+	  if (ifunc != NULL)
+	    {
+	      struct plt_entry *ent;
+
+	      for (ent = *ifunc; ent != NULL; ent = ent->next)
+		if (ent->addend == rel->r_addend)
+		  break;
+	      if (ent == NULL)
+		abort ();
+	      if (ent->plt.refcount > 0)
+		ent->plt.refcount -= 1;
+	      continue;
+	    }
+	}
+
       switch (r_type)
 	{
 	case R_PPC64_GOT_TLSLD16:
@@ -6039,6 +6162,7 @@ ppc64_elf_adjust_dynamic_symbol (struct 
 
   /* Deal with function syms.  */
   if (h->type == STT_FUNC
+      || h->type == STT_GNU_IFUNC
       || h->needs_plt)
     {
       /* Clear procedure linkage table information for any symbol that
@@ -6048,9 +6172,10 @@ ppc64_elf_adjust_dynamic_symbol (struct 
 	if (ent->plt.refcount > 0)
 	  break;
       if (ent == NULL
-	  || SYMBOL_CALLS_LOCAL (info, h)
-	  || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-	      && h->root.type == bfd_link_hash_undefweak))
+	  || (h->type != STT_GNU_IFUNC
+	      && (SYMBOL_CALLS_LOCAL (info, h)
+		  || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+		      && h->root.type == bfd_link_hash_undefweak))))
 	{
 	  h->plt.plist = NULL;
 	  h->needs_plt = 0;
@@ -6301,7 +6426,10 @@ get_sym_h (struct elf_link_hash_entry **
 	  lgot_ents = elf_local_got_ents (ibfd);
 	  if (lgot_ents != NULL)
 	    {
-	      char *lgot_masks = (char *) (lgot_ents + symtab_hdr->sh_info);
+	      struct plt_entry **local_plt = (struct plt_entry **)
+		(lgot_ents + symtab_hdr->sh_info);
+	      char *lgot_masks = (char *)
+		(local_plt + symtab_hdr->sh_info);
 	      tls_mask = &lgot_masks[r_symndx];
 	    }
 	  *tls_maskp = tls_mask;
@@ -6983,15 +7111,7 @@ branch_reloc_hash_match (const bfd *ibfd
   enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
   unsigned int r_symndx = ELF64_R_SYM (rel->r_info);
 
-  if (r_symndx >= symtab_hdr->sh_info
-      && (r_type == R_PPC64_REL24
-	  || r_type == R_PPC64_REL14
-	  || r_type == R_PPC64_REL14_BRTAKEN
-	  || r_type == R_PPC64_REL14_BRNTAKEN
-	  || r_type == R_PPC64_ADDR24
-	  || r_type == R_PPC64_ADDR14
-	  || r_type == R_PPC64_ADDR14_BRTAKEN
-	  || r_type == R_PPC64_ADDR14_BRNTAKEN))
+  if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type))
     {
       struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
       struct elf_link_hash_entry *h;
@@ -7860,37 +7980,48 @@ allocate_dynrelocs (struct elf_link_hash
   info = (struct bfd_link_info *) inf;
   htab = ppc_hash_table (info);
 
-  if (htab->elf.dynamic_sections_created
-      && h->dynindx != -1
-      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+  if ((htab->elf.dynamic_sections_created
+       && h->dynindx != -1
+       && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+      || h->type == STT_GNU_IFUNC)
     {
       struct plt_entry *pent;
       bfd_boolean doneone = FALSE;
       for (pent = h->plt.plist; pent != NULL; pent = pent->next)
 	if (pent->plt.refcount > 0)
 	  {
-	    /* If this is the first .plt entry, make room for the special
-	       first entry.  */
-	    s = htab->plt;
-	    if (s->size == 0)
-	      s->size += PLT_INITIAL_ENTRY_SIZE;
-
-	    pent->plt.offset = s->size;
-
-	    /* Make room for this entry.  */
-	    s->size += PLT_ENTRY_SIZE;
-
-	    /* Make room for the .glink code.  */
-	    s = htab->glink;
-	    if (s->size == 0)
-	      s->size += GLINK_CALL_STUB_SIZE;
-	    /* We need bigger stubs past index 32767.  */
-	    if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
-	      s->size += 4;
-	    s->size += 2*4;
+	    if (!htab->elf.dynamic_sections_created)
+	      {
+		s = htab->iplt;
+		pent->plt.offset = s->size;
+		s->size += PLT_ENTRY_SIZE;
+		s = htab->reliplt;
+	      }
+	    else
+	      {
+		/* If this is the first .plt entry, make room for the special
+		   first entry.  */
+		s = htab->plt;
+		if (s->size == 0)
+		  s->size += PLT_INITIAL_ENTRY_SIZE;
+
+		pent->plt.offset = s->size;
+
+		/* Make room for this entry.  */
+		s->size += PLT_ENTRY_SIZE;
+
+		/* Make room for the .glink code.  */
+		s = htab->glink;
+		if (s->size == 0)
+		  s->size += GLINK_CALL_STUB_SIZE;
+		/* We need bigger stubs past index 32767.  */
+		if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+		  s->size += 4;
+		s->size += 2*4;
 
-	    /* We also need to make an entry in the .rela.plt section.  */
-	    s = htab->relplt;
+		/* We also need to make an entry in the .rela.plt section.  */
+		s = htab->relplt;
+	      }
 	    s->size += sizeof (Elf64_External_Rela);
 	    doneone = TRUE;
 	  }
@@ -8133,6 +8264,8 @@ ppc64_elf_size_dynamic_sections (bfd *ou
     {
       struct got_entry **lgot_ents;
       struct got_entry **end_lgot_ents;
+      struct plt_entry **local_plt;
+      struct plt_entry **end_local_plt;
       char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
@@ -8172,7 +8305,9 @@ ppc64_elf_size_dynamic_sections (bfd *ou
       symtab_hdr = &elf_symtab_hdr (ibfd);
       locsymcount = symtab_hdr->sh_info;
       end_lgot_ents = lgot_ents + locsymcount;
-      lgot_masks = (char *) end_lgot_ents;
+      local_plt = (struct plt_entry **) end_lgot_ents;
+      end_local_plt = local_plt + locsymcount;
+      lgot_masks = (char *) end_local_plt;
       s = ppc64_elf_tdata (ibfd)->got;
       srel = ppc64_elf_tdata (ibfd)->relgot;
       for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
@@ -8207,6 +8342,25 @@ ppc64_elf_size_dynamic_sections (bfd *ou
 	    else
 	      ent->got.offset = (bfd_vma) -1;
 	}
+
+      /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
+      for (; local_plt < end_local_plt; ++local_plt)
+	{
+	  struct plt_entry *ent;
+
+	  for (ent = *local_plt; ent != NULL; ent = ent->next)
+	    if (ent->plt.refcount > 0)
+	      {
+		asection *s = htab->iplt;
+
+		ent->plt.offset = s->size;
+		s->size += PLT_ENTRY_SIZE;
+
+		htab->reliplt += sizeof (Elf64_External_Rela);
+	      }
+	    else
+	      ent->plt.offset = (bfd_vma) -1;
+	}
     }
 
   /* Allocate global sym .plt and .got entries, and space for global
@@ -8246,6 +8400,7 @@ ppc64_elf_size_dynamic_sections (bfd *ou
 	continue;
       else if (s == htab->got
 	       || s == htab->plt
+	       || s == htab->iplt
 	       || s == htab->glink
 	       || s == htab->dynbss)
 	{
@@ -8396,6 +8551,7 @@ static inline enum ppc_stub_type
 ppc_type_of_stub (asection *input_sec,
 		  const Elf_Internal_Rela *rel,
 		  struct ppc_link_hash_entry **hash,
+		  struct plt_entry **plt_ent,
 		  bfd_vma destination)
 {
   struct ppc_link_hash_entry *h = *hash;
@@ -8406,23 +8562,20 @@ ppc_type_of_stub (asection *input_sec,
 
   if (h != NULL)
     {
+      struct plt_entry *ent;
       struct ppc_link_hash_entry *fdh = h;
       if (fdh->oh != NULL
 	  && fdh->oh->is_func_descriptor)
 	fdh = fdh->oh;
 
-      if (fdh->elf.dynindx != -1)
-	{
-	  struct plt_entry *ent;
-
-	  for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
-	    if (ent->addend == rel->r_addend
-		&& ent->plt.offset != (bfd_vma) -1)
-	      {
-		*hash = fdh;
-		return ppc_stub_plt_call;
-	      }
-	}
+      for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
+	if (ent->addend == rel->r_addend
+	    && ent->plt.offset != (bfd_vma) -1)
+	  {
+	    *hash = fdh;
+	    *plt_ent = ent;
+	    return ppc_stub_plt_call;
+	  }
 
       /* Here, we know we don't have a plt entry.  If we don't have a
 	 either a defined function descriptor or a defined entry symbol
@@ -8436,6 +8589,26 @@ ppc_type_of_stub (asection *input_sec,
 	       && h->elf.root.u.def.section->output_section != NULL))
 	return ppc_stub_none;
     }
+  else if (elf_local_got_ents (input_sec->owner) != NULL)
+    {
+      Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_sec->owner);
+      struct plt_entry **local_plt = (struct plt_entry **)
+	elf_local_got_ents (input_sec->owner) + symtab_hdr->sh_info;
+      unsigned long r_symndx = ELF64_R_SYM (rel->r_info);
+
+      if (local_plt[r_symndx] != NULL)
+	{
+	  struct plt_entry *ent;
+
+	  for (ent = local_plt[r_symndx]; ent != NULL; ent = ent->next)
+	    if (ent->addend == rel->r_addend
+		&& ent->plt.offset != (bfd_vma) -1)
+	      {
+		*plt_ent = ent;
+		return ppc_stub_plt_call;
+	      }
+	}
+    }
 
   /* Determine where the call point is.  */
   location = (input_sec->output_offset
@@ -8576,10 +8749,10 @@ ppc_build_one_stub (struct bfd_hash_entr
   struct ppc_link_hash_table *htab;
   bfd_byte *loc;
   bfd_byte *p;
-  struct plt_entry *ent;
   bfd_vma dest, off;
   int size;
   Elf_Internal_Rela *r;
+  asection *plt;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
@@ -8835,7 +9008,8 @@ ppc_build_one_stub (struct bfd_hash_entr
       /* Do the best we can for shared libraries built without
 	 exporting ".foo" for each "foo".  This can happen when symbol
 	 versioning scripts strip all bar a subset of symbols.  */
-      if (stub_entry->h->oh != NULL
+      if (stub_entry->h != NULL
+	  && stub_entry->h->oh != NULL
 	  && stub_entry->h->oh->elf.root.type != bfd_link_hash_defined
 	  && stub_entry->h->oh->elf.root.type != bfd_link_hash_defweak)
 	{
@@ -8850,29 +9024,51 @@ ppc_build_one_stub (struct bfd_hash_entr
 	}
 
       /* Now build the stub.  */
-      dest = (bfd_vma) -1;
-      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
-	if (ent->addend == stub_entry->addend)
-	  {
-	    dest = ent->plt.offset;
-	    break;
-	  }
+      dest = stub_entry->plt_ent->plt.offset & ~1;
       if (dest >= (bfd_vma) -2)
 	abort ();
 
-      dest &= ~ (bfd_vma) 1;
-      dest += (htab->plt->output_offset
-	       + htab->plt->output_section->vma);
+      plt = htab->plt;
+      if (!htab->elf.dynamic_sections_created)
+	plt = htab->iplt;
+
+      dest += plt->output_offset + plt->output_section->vma;
+
+      if (stub_entry->h == NULL
+	  && (stub_entry->plt_ent->plt.offset & 1) == 0)
+	{
+	  Elf_Internal_Rela rela;
+	  bfd_byte *rl;
+
+	  rela.r_offset = dest;
+	  rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+	  rela.r_addend = (stub_entry->target_value
+			   + stub_entry->target_section->output_offset
+			   + stub_entry->target_section->output_section->vma);
+
+	  if (!htab->elf.dynamic_sections_created)
+	    rl = (htab->reliplt->contents
+		  + (stub_entry->plt_ent->plt.offset
+		     / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
+	  else
+	    rl = (htab->relplt->contents
+		  + ((stub_entry->plt_ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
+		     / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
+	  bfd_elf32_swap_reloca_out (info->output_bfd, &rela, rl);
+	  stub_entry->plt_ent->plt.offset |= 1;
+	}
 
       off = (dest
-	     - elf_gp (htab->plt->output_section->owner)
+	     - elf_gp (plt->output_section->owner)
 	     - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
 	{
 	  (*_bfd_error_handler)
 	    (_("linkage table error against `%s'"),
-	     stub_entry->h->elf.root.root.string);
+	     stub_entry->h != NULL
+	     ? stub_entry->h->elf.root.root.string
+	     : "<local sym>");
 	  bfd_set_error (bfd_error_bad_value);
 	  htab->stub_error = TRUE;
 	  return FALSE;
@@ -8961,19 +9157,16 @@ ppc_size_one_stub (struct bfd_hash_entry
 
   if (stub_entry->stub_type == ppc_stub_plt_call)
     {
-      struct plt_entry *ent;
-      off = (bfd_vma) -1;
-      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
-	if (ent->addend == stub_entry->addend)
-	  {
-	    off = ent->plt.offset & ~(bfd_vma) 1;
-	    break;
-	  }
+      asection *plt;
+      off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
       if (off >= (bfd_vma) -2)
 	abort ();
-      off += (htab->plt->output_offset
-	      + htab->plt->output_section->vma
-	      - elf_gp (htab->plt->output_section->owner)
+      plt = htab->plt;
+      if (!htab->elf.dynamic_sections_created)
+	plt = htab->iplt;
+      off += (plt->output_offset
+	      + plt->output_section->vma
+	      - elf_gp (plt->output_section->owner)
 	      - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
       size = PLT_CALL_STUB_SIZE;
@@ -9647,7 +9840,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 		  enum ppc_stub_type stub_type;
 		  struct ppc_stub_hash_entry *stub_entry;
 		  asection *sym_sec, *code_sec;
-		  bfd_vma sym_value;
+		  bfd_vma sym_value, code_value;
 		  bfd_vma destination;
 		  bfd_boolean ok_dest;
 		  struct ppc_link_hash_entry *hash;
@@ -9657,6 +9850,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 		  char *stub_name;
 		  const asection *id_sec;
 		  struct _opd_sec_data *opd;
+		  struct plt_entry *plt_ent;
 
 		  r_type = ELF64_R_TYPE (irela->r_info);
 		  r_indx = ELF64_R_SYM (irela->r_info);
@@ -9733,6 +9927,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 		    }
 
 		  code_sec = sym_sec;
+		  code_value = sym_value;
 		  opd = get_opd_info (sym_sec);
 		  if (opd != NULL)
 		    {
@@ -9743,10 +9938,11 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 			  long adjust = opd->adjust[sym_value / 8];
 			  if (adjust == -1)
 			    continue;
+			  code_value += adjust;
 			  sym_value += adjust;
 			}
 		      dest = opd_entry_value (sym_sec, sym_value,
-					      &code_sec, &sym_value);
+					      &code_sec, &code_value);
 		      if (dest != (bfd_vma) -1)
 			{
 			  destination = dest;
@@ -9756,14 +9952,15 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 				 entry.  */
 			      hash->elf.root.type = bfd_link_hash_defweak;
 			      hash->elf.root.u.def.section = code_sec;
-			      hash->elf.root.u.def.value = sym_value;
+			      hash->elf.root.u.def.value = code_value;
 			    }
 			}
 		    }
 
 		  /* Determine what (if any) linker stub is needed.  */
+		  plt_ent = NULL;
 		  stub_type = ppc_type_of_stub (section, irela, &hash,
-						destination);
+						&plt_ent, destination);
 
 		  if (stub_type != ppc_stub_plt_call)
 		    {
@@ -9836,9 +10033,18 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 		    }
 
 		  stub_entry->stub_type = stub_type;
-		  stub_entry->target_value = sym_value;
-		  stub_entry->target_section = code_sec;
+		  if (stub_type != ppc_stub_plt_call)
+		    {
+		      stub_entry->target_value = code_value;
+		      stub_entry->target_section = code_sec;
+		    }
+		  else
+		    {
+		      stub_entry->target_value = sym_value;
+		      stub_entry->target_section = sym_sec;
+		    }
 		  stub_entry->h = hash;
+		  stub_entry->plt_ent = plt_ent;
 		  stub_entry->addend = irela->r_addend;
 
 		  if (stub_entry->h != NULL)
@@ -9924,13 +10130,13 @@ ppc64_elf_toc (bfd *obfd)
   /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
      order.  The TOC starts where the first of these sections starts.  */
   s = bfd_get_section_by_name (obfd, ".got");
-  if (s == NULL)
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
     s = bfd_get_section_by_name (obfd, ".toc");
-  if (s == NULL)
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
     s = bfd_get_section_by_name (obfd, ".tocbss");
-  if (s == NULL)
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
     s = bfd_get_section_by_name (obfd, ".plt");
-  if (s == NULL)
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
     {
       /* This may happen for
 	 o  references to TOC base (SYM@toc / TOC[tc0]) without a
@@ -9943,21 +10149,23 @@ ppc64_elf_toc (bfd *obfd)
       /* Look for a likely section.  We probably won't even be
 	 using TOCstart.  */
       for (s = obfd->sections; s != NULL; s = s->next)
-	if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
+	if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY
+			 | SEC_EXCLUDE))
 	    == (SEC_ALLOC | SEC_SMALL_DATA))
 	  break;
       if (s == NULL)
 	for (s = obfd->sections; s != NULL; s = s->next)
-	  if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
+	  if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_EXCLUDE))
 	      == (SEC_ALLOC | SEC_SMALL_DATA))
 	    break;
       if (s == NULL)
 	for (s = obfd->sections; s != NULL; s = s->next)
-	  if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
+	  if ((s->flags & (SEC_ALLOC | SEC_READONLY | SEC_EXCLUDE))
+	      == SEC_ALLOC)
 	    break;
       if (s == NULL)
 	for (s = obfd->sections; s != NULL; s = s->next)
-	  if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
+	  if ((s->flags & (SEC_ALLOC | SEC_EXCLUDE)) == SEC_ALLOC)
 	    break;
     }
 
@@ -10386,8 +10594,10 @@ ppc64_elf_relocate_section (bfd *output_
 	tls_mask = h->tls_mask;
       else if (local_got_ents != NULL)
 	{
-	  char *lgot_masks;
-	  lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
+	  struct plt_entry **local_plt = (struct plt_entry **)
+	    (local_got_ents + symtab_hdr->sh_info);
+	  char *lgot_masks = (char *)
+	    (local_plt + symtab_hdr->sh_info);
 	  tls_mask = lgot_masks[r_symndx];
 	}
       if (tls_mask == 0
@@ -11827,23 +12037,41 @@ ppc64_elf_finish_dynamic_symbol (bfd *ou
       {
 	/* This symbol has an entry in the procedure linkage
 	   table.  Set it up.  */
+	asection *plt = htab->plt;
+	if (!htab->elf.dynamic_sections_created)
+	  plt = htab->iplt;
 
-	if (htab->plt == NULL
-	    || htab->relplt == NULL
-	    || htab->glink == NULL)
-	  abort ();
-
-	/* Create a JMP_SLOT reloc to inform the dynamic linker to
-	   fill in the PLT entry.  */
-	rela.r_offset = (htab->plt->output_section->vma
-			 + htab->plt->output_offset
+	rela.r_offset = (plt->output_section->vma
+			 + plt->output_offset
 			 + ent->plt.offset);
-	rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
-	rela.r_addend = ent->addend;
 
-	loc = htab->relplt->contents;
-	loc += ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
-		* sizeof (Elf64_External_Rela));
+	if (!htab->elf.dynamic_sections_created
+	    || h->dynindx == -1)
+	  {
+	    BFD_ASSERT (h->type == STT_GNU_IFUNC
+			&& h->def_regular
+			&& (h->root.type == bfd_link_hash_defined
+			    || h->root.type == bfd_link_hash_defweak));
+	    rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+	    rela.r_addend = (h->root.u.def.value
+			     + h->root.u.def.section->output_offset
+			     + h->root.u.def.section->output_section->vma
+			     + ent->addend);
+	  }
+	else
+	  {
+	    rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
+	    rela.r_addend = ent->addend;
+	  }
+
+	if (!htab->elf.dynamic_sections_created)
+	  loc = (htab->reliplt->contents
+		 + (ent->plt.offset
+		    / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
+	else
+	  loc = (htab->relplt->contents
+		 + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
+		    / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
 	bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
       }
 
Index: ld/emulparams/elf32ppc.sh
===================================================================
RCS file: /cvs/src/src/ld/emulparams/elf32ppc.sh,v
retrieving revision 1.21
diff -u -p -r1.21 elf32ppc.sh
--- ld/emulparams/elf32ppc.sh	7 May 2008 14:46:44 -0000	1.21
+++ ld/emulparams/elf32ppc.sh	10 Jul 2009 10:59:33 -0000
@@ -10,8 +10,9 @@ SDATA_GOT=
 SEPARATE_GOTPLT=0
 BSS_PLT=
 GOT=".got          ${RELOCATING-0} : SPECIAL { *(.got) }"
-PLT=".plt          ${RELOCATING-0} : SPECIAL { *(.plt) }"
-GOTPLT="${PLT}"
+GOTPLT=".plt          ${RELOCATING-0} : SPECIAL { *(.plt) }"
+PLT=".plt          ${RELOCATING-0} : SPECIAL { *(.plt) *(.iplt) }
+  .iplt         ${RELOCATING-0} : { *(.iplt) }"
 OTHER_TEXT_SECTIONS="*(.glink)"
 EXTRA_EM_FILE=ppc32elf
 if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then
Index: ld/testsuite/ld-ifunc/ifunc.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-ifunc/ifunc.exp,v
retrieving revision 1.2
diff -u -p -r1.2 ifunc.exp
--- ld/testsuite/ld-ifunc/ifunc.exp	1 Jun 2009 13:11:52 -0000	1.2
+++ ld/testsuite/ld-ifunc/ifunc.exp	10 Jul 2009 08:09:20 -0000
@@ -23,11 +23,15 @@
 # Written by Nick Clifton <nickc@redhat.com>
 
 
-# IFUNC support has only been implemented for the x86_64 and ix86 so far.
-if {! (  [istarget "x86_64-*-elf*"]
-      || [istarget "x86_64-*-linux*"]
-      || [istarget "i?86-*-elf*"]
-      || [istarget "i?86-*-linux*"]) } {
+# IFUNC support has only been implemented for the ix86, x86_64 and powerpc
+# so far.
+if {!(([istarget "i?86-*-*"]
+       || [istarget "x86_64-*-*"]
+       || [istarget "powerpc*-*-*"])
+      && ([istarget "*-*-elf*"]
+	  || ([istarget "*-*-linux*"]
+	      && ![istarget "*-*-*aout*"]
+	      && ![istarget "*-*-*oldld*"]))) } {
     verbose "IFUNC tests not run - target does not support IFUNC"
     return
 }
@@ -195,11 +199,15 @@ if ![default_ld_link $ld "tmpdir/dynamic
     fail "Could not link a dynamic executable"
     set fails [expr $fails + 1]
 }
-if ![default_ld_link $ld "tmpdir/static_prog" "-Ltmpdir tmpdir/static_prog.o -lifunc"] {
+if ![default_ld_link $ld "tmpdir/local_prog" "-Ltmpdir tmpdir/static_prog.o -lifunc"] {
+    fail "Could not link a dynamic executable using local ifunc"
+    set fails [expr $fails + 1]
+}
+if ![default_ld_link $ld "tmpdir/static_prog" "-static -Ltmpdir tmpdir/static_prog.o -lifunc"] {
     fail "Could not link a static executable"
     set fails [expr $fails + 1]
 }
-if ![default_ld_link $ld "tmpdir/static_nonifunc_prog" "-Ltmpdir tmpdir/static_prog.o tmpdir/static_noifunc.o"] {
+if ![default_ld_link $ld "tmpdir/static_nonifunc_prog" "-static -Ltmpdir tmpdir/static_prog.o tmpdir/static_noifunc.o"] {
     fail "Could not link a non-ifunc using static executable"
     set fails [expr $fails + 1]
 }
@@ -221,6 +229,10 @@ if {! [check_osabi tmpdir/libshared_ifun
     fail "Shared libraries containing ifunc does not have an OS/ABI field of LINUX"
     set fails [expr $fails + 1]
 }
+if {! [check_osabi tmpdir/local_prog {UNIX - Linux}]} {
+    fail "Local ifunc-using executable 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]
@@ -242,6 +254,10 @@ if {[contains_ifunc_symbol tmpdir/libsha
     fail "Shared libraries containing ifunc does not contain an IFUNC symbol"
     set fails [expr $fails + 1]
 }
+if {[contains_ifunc_symbol tmpdir/local_prog] != 1} {
+    fail "Local ifunc-using executable 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]
@@ -264,6 +280,10 @@ if {[contains_irelative_reloc tmpdir/lib
     fail "ifunc-using shared library does not contain R_*_IRELATIVE relocation"
     set fails [expr $fails + 1]
 }
+if {[contains_irelative_reloc tmpdir/local_prog] != 1} {
+    fail "Local ifunc-using executable 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]
@@ -291,6 +311,7 @@ if { $verbose < 1 } {
     remote_file host delete "tmpdir/libshared_ifunc.so"
     remote_file host delete "tmpdir/libifunc.a"
     remote_file host delete "tmpdir/dynamic_prog"
+    remote_file host delete "tmpdir/local_prog"
     remote_file host delete "tmpdir/static_prog"
     remote_file host delete "tmpdir/static_nonifunc_prog"
 }

-- 
Alan Modra
Australia Development Lab, IBM


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