PowerPC ifunc with local symbols

Alan Modra amodra@gmail.com
Mon Dec 7 03:23:00 GMT 2015


This fixes some cases where the linker would incorrectly error on plt
relocs to local ifunc symbols.  I've also tidied plt and ifunc
handling for ppc64, where check_relocs was allowing for the
possibility of plt calls via addr14/addr24 relocs but relocate_section
was not.

	* elf32-ppc.c (ppc_elf_check_relocs): Don't error on local ifunc
	plt call.  Wrap long lines.
	(ppc_elf_relocate_section): Wrap long lines.
	* elf64-ppc.c (ppc64_elf_check_relocs): Don't error on local ifunc
	plt calls.  Move __tls_get_addr checks later.  Don't create plt
	for addr14/addr24 relocs.
	(ppc64_elf_gc_sweep_hook): Adjust to suit check_relocs changes.
	(ppc64_elf_relocate_section): Correct local ifunc handling for
	PLT64, PLT32 and PLT16 relocs.

diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 017de65..ea03598 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -3948,6 +3948,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)
@@ -3980,6 +3981,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
       tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
+      ifunc = NULL;
       if (h == NULL && !htab->is_vxworks)
 	{
 	  Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
@@ -3989,8 +3991,6 @@ ppc_elf_check_relocs (bfd *abfd,
 
 	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
 	    {
-	      struct plt_entry **ifunc;
-
 	      /* Set PLT_IFUNC flag for this sym, no GOT entry yet.  */
 	      ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
 					     PLT_IFUNC);
@@ -4224,21 +4224,20 @@ ppc_elf_check_relocs (bfd *abfd,
 #ifdef DEBUG
 	  fprintf (stderr, "Reloc requires a PLT entry\n");
 #endif
-	  /* This symbol requires a procedure linkage table entry.  We
-	     actually build the entry in finish_dynamic_symbol,
-	     because this might be a case of linking PIC code without
-	     linking in any dynamic objects, in which case we don't
-	     need to generate a procedure linkage table after all.  */
-
+	  /* This symbol requires a procedure linkage table entry.  */
 	  if (h == NULL)
 	    {
-	      /* It does not make sense to have a procedure linkage
-		 table entry for a local symbol.  */
-	      info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"),
-				      abfd, sec, rel->r_offset,
-				      ppc_elf_howto_table[r_type]->name);
-	      bfd_set_error (bfd_error_bad_value);
-	      return FALSE;
+	      if (ifunc == NULL)
+		{
+		  /* It does not make sense to have a procedure linkage
+		     table entry for a non-ifunc local symbol.  */
+		  info->callbacks->einfo
+		    (_("%P: %H: %s reloc against local symbol\n"),
+		     abfd, sec, rel->r_offset,
+		     ppc_elf_howto_table[r_type]->name);
+		  bfd_set_error (bfd_error_bad_value);
+		  return FALSE;
+		}
 	    }
 	  else
 	    {
@@ -4316,9 +4315,10 @@ ppc_elf_check_relocs (bfd *abfd,
 	    {
 	      if (bfd_link_pic (info))
 		{
-		  info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
-					  abfd, sec, rel->r_offset,
-					  h->root.root.string);
+		  info->callbacks->einfo
+		    (_("%P: %H: @local call to ifunc %s\n"),
+		     abfd, sec, rel->r_offset,
+		     h->root.root.string);
 		  bfd_set_error (bfd_error_bad_value);
 		  return FALSE;
 		}
@@ -8968,8 +8968,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	case R_PPC_PLTREL24:
 	  if (h != NULL && ifunc == NULL)
 	    {
-	      struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
-						    bfd_link_pic (info) ? addend : 0);
+	      struct plt_entry *ent;
+
+	      ent = find_plt_ent (&h->plt.plist, got2,
+				  bfd_link_pic (info) ? addend : 0);
 	      if (ent == NULL
 		  || htab->plt == NULL)
 		{
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 303170b..94c0f23 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -5340,7 +5340,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       enum elf_ppc64_reloc_type r_type;
       int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
-      struct plt_entry **ifunc;
+      struct plt_entry **ifunc, **plt_list;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -5383,28 +5383,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 		return FALSE;
 	    }
 	}
-      r_type = ELF64_R_TYPE (rel->r_info);
-      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;
-	    }
-
-	  /* STT_GNU_IFUNC symbols must have a PLT entry.  */
-	  if (ifunc != NULL
-	      && !update_plt_info (abfd, ifunc, rel->r_addend))
-	    return FALSE;
-	}
 
+      r_type = ELF64_R_TYPE (rel->r_info);
       switch (r_type)
 	{
 	case R_PPC64_TLSGD:
@@ -5516,27 +5496,29 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_PLT16_LO:
 	case R_PPC64_PLT32:
 	case R_PPC64_PLT64:
-	  /* This symbol requires a procedure linkage table entry.  We
-	     actually build the entry in adjust_dynamic_symbol,
-	     because this might be a case of linking PIC code without
-	     linking in any dynamic objects, in which case we don't
-	     need to generate a procedure linkage table after all.  */
-	  if (h == NULL)
-	    {
-	      /* It does not make sense to have a procedure linkage
-		 table entry for a local symbol.  */
-	      bfd_set_error (bfd_error_bad_value);
-	      return FALSE;
-	    }
-	  else
+	  /* This symbol requires a procedure linkage table entry.  */
+	  plt_list = ifunc;
+	  if (h != NULL)
 	    {
-	      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;
+	      plt_list = &h->plt.plist;
+	    }
+	  if (plt_list == NULL)
+	    {
+	      /* It does not make sense to have a procedure linkage
+		 table entry for a non-ifunc local symbol.  */
+	      info->callbacks->einfo
+		(_("%P: %H: %s reloc against local symbol\n"),
+		 abfd, sec, rel->r_offset,
+		 ppc64_elf_howto_table[r_type]->name);
+	      bfd_set_error (bfd_error_bad_value);
+	      return FALSE;
 	    }
+	  if (!update_plt_info (abfd, plt_list, rel->r_addend))
+	    return FALSE;
 	  break;
 
 	  /* The following relocations don't need to propagate the
@@ -5649,21 +5631,43 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	  /* Fall through.  */
 
 	case R_PPC64_REL24:
-	  if (h != NULL && ifunc == NULL)
+	  plt_list = ifunc;
+	  if (h != NULL)
 	    {
-	      /* We may need a .plt entry if the function this reloc
-		 refers to is in a shared lib.  */
-	      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;
+		{
+		  sec->has_tls_reloc = 1;
+		  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;
+		}
+	      plt_list = &h->plt.plist;
 	    }
+
+	  /* We may need a .plt entry if the function this reloc
+	     refers to is in a shared lib.  */
+	  if (plt_list
+	      && !update_plt_info (abfd, plt_list, rel->r_addend))
+	    return FALSE;
 	  break;
 
+	case R_PPC64_ADDR14:
+	case R_PPC64_ADDR14_BRNTAKEN:
+	case R_PPC64_ADDR14_BRTAKEN:
+	case R_PPC64_ADDR24:
+	  goto dodyn;
+
 	case R_PPC64_TPREL64:
 	  tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
 	  if (bfd_link_pic (info))
@@ -5806,10 +5810,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_REL30:
 	case R_PPC64_REL32:
 	case R_PPC64_REL64:
-	case R_PPC64_ADDR14:
-	case R_PPC64_ADDR14_BRNTAKEN:
-	case R_PPC64_ADDR14_BRTAKEN:
-	case R_PPC64_ADDR24:
 	case R_PPC64_ADDR32:
 	case R_PPC64_UADDR16:
 	case R_PPC64_UADDR32:
@@ -6505,6 +6505,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       enum elf_ppc64_reloc_type r_type;
       struct elf_link_hash_entry *h = NULL;
+      struct plt_entry **plt_list;
       unsigned char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -6528,38 +6529,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
 	      }
 	}
 
-      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);
-	      unsigned char *local_got_tls_masks = (unsigned 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:
@@ -6626,11 +6595,23 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_REL14_BRNTAKEN:
 	case R_PPC64_REL14_BRTAKEN:
 	case R_PPC64_REL24:
+	  plt_list = NULL;
 	  if (h != NULL)
+	    plt_list = &h->plt.plist;
+	  else if (local_got_ents != NULL)
+	    {
+	      struct plt_entry **local_plt = (struct plt_entry **)
+		(local_got_ents + symtab_hdr->sh_info);
+	      unsigned char *local_got_tls_masks = (unsigned char *)
+		(local_plt + symtab_hdr->sh_info);
+	      if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+		plt_list = local_plt + r_symndx;
+	    }
+	  if (plt_list)
 	    {
 	      struct plt_entry *ent;
 
-	      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+	      for (ent = *plt_list; ent != NULL; ent = ent->next)
 		if (ent->addend == rel->r_addend)
 		  break;
 	      if (ent != NULL && ent->plt.refcount > 0)
@@ -14488,30 +14469,43 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	case R_PPC64_PLT64:
 	  /* Relocation is to the entry for this symbol in the
 	     procedure linkage table.  */
+	  {
+	    struct plt_entry **plt_list = NULL;
+	    if (h != NULL)
+	      plt_list = &h->elf.plt.plist;
+	    else if (local_got_ents != NULL)
+	      {
+		struct plt_entry **local_plt = (struct plt_entry **)
+		  (local_got_ents + symtab_hdr->sh_info);
+		unsigned char *local_got_tls_masks = (unsigned char *)
+		  (local_plt + symtab_hdr->sh_info);
+		if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+		  plt_list = local_plt + r_symndx;
+	      }
+	    if (plt_list)
+	      {
+		struct plt_entry *ent;
 
-	  /* Resolve a PLT reloc against a local symbol directly,
-	     without using the procedure linkage table.  */
-	  if (h == NULL)
-	    break;
-
-	  /* It's possible that we didn't make a PLT entry for this
-	     symbol.  This happens when statically linking PIC code,
-	     or when using -Bsymbolic.  Go find a match if there is a
-	     PLT entry.  */
-	  if (htab->elf.splt != NULL)
-	    {
-	      struct plt_entry *ent;
-	      for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
-		if (ent->plt.offset != (bfd_vma) -1
-		    && ent->addend == orig_rel.r_addend)
-		  {
-		    relocation = (htab->elf.splt->output_section->vma
-				  + htab->elf.splt->output_offset
-				  + ent->plt.offset);
-		    unresolved_reloc = FALSE;
-		    break;
-		  }
-	    }
+		for (ent = *plt_list; ent != NULL; ent = ent->next)
+		  if (ent->plt.offset != (bfd_vma) -1
+		      && ent->addend == orig_rel.r_addend)
+		    {
+		      asection *plt;
+
+		      plt = htab->elf.splt;
+		      if (!htab->elf.dynamic_sections_created
+			  || h == NULL
+			  || h->elf.dynindx == -1)
+			plt = htab->elf.iplt;
+		      relocation = (plt->output_section->vma
+				    + plt->output_offset
+				    + ent->plt.offset);
+		      addend = 0;
+		      unresolved_reloc = FALSE;
+		      break;
+		    }
+	      }
+	  }
 	  break;
 
 	case R_PPC64_TOC:

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list