This is the mail archive of the binutils-cvs@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]

[binutils-gdb/binutils-2_26-branch] PowerPC ifunc with local symbols


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b0aafdad68a983b5bd45e7d7f55fec1fbcea9e84

commit b0aafdad68a983b5bd45e7d7f55fec1fbcea9e84
Author: Alan Modra <amodra@gmail.com>
Date:   Mon Dec 7 13:52:01 2015 +1030

    PowerPC ifunc with local symbols
    
    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:
---
 bfd/ChangeLog   |  11 ++++
 bfd/elf32-ppc.c |  42 ++++++------
 bfd/elf64-ppc.c | 200 +++++++++++++++++++++++++++-----------------------------
 3 files changed, 130 insertions(+), 123 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 0dc691d..1b8cce7 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -2,6 +2,17 @@
 
 	Apply from master.
 	2015-12-07  Alan Modra  <amodra@gmail.com>
+	* 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.
+
+	2015-12-07  Alan Modra  <amodra@gmail.com>
 	PR 19323
 	* elfcode.h (elf_object_p): Check for ridiculous e_shnum and
 	e_phnum values.
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 17b7a13..162862c 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)
@@ -14485,30 +14466,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:


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