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]

Rearrange PLT reloc output on powerpc


The current scheme where we output PLT relocs for global symbols in
finish_dynamic_symbol, and PLT relocs for local symbols when
outputting stubs does not work if PLT entries are to be used for
inline PLT sequences against non-dynamic globals or local symbols.

bfd/
	* elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs
	for local symbols to..
	(write_plt_relocs_for_local_syms): ..here.  New function.
	(ppc64_elf_finish_dynamic_symbol): Move output of PLT relocs for
	global symbols to..
	(build_global_entry_stubs_and_plt): ..here.  Rename from
	build_global_entry_stubs.
	(ppc64_elf_build_stubs): Always call build_global_entry_stubs_and_plt.
	Call write_plt_relocs_for_local_syms.
	* elf32-ppc.c (get_sym_h): New function.
	(ppc_elf_relax_section): Use get_sym_h.
	(ppc_elf_relocate_section): Move output of PLT relocs and glink
	stubs for local symbols to..
	(ppc_finish_symbols): ..here.  New function.
	(ppc_elf_finish_dynamic_symbol): Move output of PLT relocs for
	global syms to..
	(write_global_sym_plt): ..here.  New function.
	* elf32-ppc.h (ppc_elf_modify_segment_map): Delete attribute.
	(ppc_finish_symbols): Declare.
ld/
	* ppc32elf.em (ppc_finish): Call ppc_finish_symbols.

diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 9736301..d24b095 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -5085,6 +5085,93 @@ ppc_elf_gc_mark_hook (asection *sec,
 
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
+
+static bfd_boolean
+get_sym_h (struct elf_link_hash_entry **hp,
+	   Elf_Internal_Sym **symp,
+	   asection **symsecp,
+	   unsigned char **tls_maskp,
+	   Elf_Internal_Sym **locsymsp,
+	   unsigned long r_symndx,
+	   bfd *ibfd)
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+
+  if (r_symndx >= symtab_hdr->sh_info)
+    {
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
+
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+	     || h->root.type == bfd_link_hash_warning)
+	h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+      if (hp != NULL)
+	*hp = h;
+
+      if (symp != NULL)
+	*symp = NULL;
+
+      if (symsecp != NULL)
+	{
+	  asection *symsec = NULL;
+	  if (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	    symsec = h->root.u.def.section;
+	  *symsecp = symsec;
+	}
+
+      if (tls_maskp != NULL)
+	*tls_maskp = &ppc_elf_hash_entry (h)->tls_mask;
+    }
+  else
+    {
+      Elf_Internal_Sym *sym;
+      Elf_Internal_Sym *locsyms = *locsymsp;
+
+      if (locsyms == NULL)
+	{
+	  locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+	  if (locsyms == NULL)
+	    locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+					    symtab_hdr->sh_info,
+					    0, NULL, NULL, NULL);
+	  if (locsyms == NULL)
+	    return FALSE;
+	  *locsymsp = locsyms;
+	}
+      sym = locsyms + r_symndx;
+
+      if (hp != NULL)
+	*hp = NULL;
+
+      if (symp != NULL)
+	*symp = sym;
+
+      if (symsecp != NULL)
+	*symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx);
+
+      if (tls_maskp != NULL)
+	{
+	  bfd_signed_vma *local_got;
+	  unsigned char *tls_mask;
+
+	  tls_mask = NULL;
+	  local_got = elf_local_got_refcounts (ibfd);
+	  if (local_got != NULL)
+	    {
+	      struct plt_entry **local_plt = (struct plt_entry **)
+		(local_got + symtab_hdr->sh_info);
+	      unsigned char *lgot_masks = (unsigned char *)
+		(local_plt + symtab_hdr->sh_info);
+	      tls_mask = &lgot_masks[r_symndx];
+	    }
+	  *tls_maskp = tls_mask;
+	}
+    }
+  return TRUE;
+}
 
 /* Set plt output section type, htab->tls_get_addr, and call the
    generic ELF tls_setup function.  */
@@ -6892,6 +6979,7 @@ ppc_elf_relax_section (bfd *abfd,
 	  bfd_byte *hit_addr;
 	  unsigned long t0;
 	  struct elf_link_hash_entry *h;
+	  Elf_Internal_Sym *isym;
 	  struct plt_entry **plist;
 	  unsigned char sym_type;
 
@@ -6919,57 +7007,34 @@ ppc_elf_relax_section (bfd *abfd,
 	    }
 
 	  /* Get the value of the symbol referred to by the reloc.  */
-	  h = NULL;
-	  if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
-	    {
-	      /* A local symbol.  */
-	      Elf_Internal_Sym *isym;
+	  if (!get_sym_h (&h, &isym, &tsec, NULL, &isymbuf,
+			  ELF32_R_SYM (irel->r_info), abfd))
+	    goto error_return;
 
-	      /* Read this BFD's local symbols.  */
-	      if (isymbuf == NULL)
-		{
-		  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
-		  if (isymbuf == NULL)
-		    isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
-						    symtab_hdr->sh_info, 0,
-						    NULL, NULL, NULL);
-		  if (isymbuf == 0)
-		    goto error_return;
-		}
-	      isym = isymbuf + ELF32_R_SYM (irel->r_info);
-	      if (isym->st_shndx == SHN_UNDEF)
+	  if (isym != NULL)
+	    {
+	      if (tsec != NULL)
+		;
+	      else if (isym->st_shndx == SHN_UNDEF)
 		tsec = bfd_und_section_ptr;
 	      else if (isym->st_shndx == SHN_ABS)
 		tsec = bfd_abs_section_ptr;
 	      else if (isym->st_shndx == SHN_COMMON)
 		tsec = bfd_com_section_ptr;
-	      else
-		tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
 	      toff = isym->st_value;
 	      sym_type = ELF_ST_TYPE (isym->st_info);
 	    }
 	  else
 	    {
-	      /* Global symbol handling.  */
-	      unsigned long indx;
-
-	      indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
-	      h = elf_sym_hashes (abfd)[indx];
-
-	      while (h->root.type == bfd_link_hash_indirect
-		     || h->root.type == bfd_link_hash_warning)
-		h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-	      if (h->root.type == bfd_link_hash_defined
-		  || h->root.type == bfd_link_hash_defweak)
-		{
-		  tsec = h->root.u.def.section;
-		  toff = h->root.u.def.value;
-		}
+	      if (tsec != NULL)
+		toff = h->root.u.def.value;
 	      else if (h->root.type == bfd_link_hash_undefined
 		       || h->root.type == bfd_link_hash_undefweak)
 		{
+		  unsigned long indx;
+
+		  indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
 		  tsec = bfd_und_section_ptr;
 		  toff = bfd_link_relocatable (link_info) ? indx : 0;
 		}
@@ -8308,32 +8373,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
 		      (_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"),
 		       input_bfd, input_section, rel->r_offset, sym_name);
 		}
-	      if (h == NULL && (ent->plt.offset & 1) == 0)
-		{
-		  Elf_Internal_Rela rela;
-		  bfd_byte *loc;
-
-		  rela.r_offset = (htab->elf.iplt->output_section->vma
-				   + htab->elf.iplt->output_offset
-				   + ent->plt.offset);
-		  rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
-		  rela.r_addend = relocation;
-		  loc = htab->elf.irelplt->contents;
-		  loc += (htab->elf.irelplt->reloc_count++
-			  * sizeof (Elf32_External_Rela));
-		  bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-		  htab->local_ifunc_resolver = 1;
-
-		  ent->plt.offset |= 1;
-		}
-	      if (h == NULL && (ent->glink_offset & 1) == 0)
-		{
-		  unsigned char *p = ((unsigned char *) htab->glink->contents
-				      + ent->glink_offset);
-
-		  write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
-		  ent->glink_offset |= 1;
-		}
 
 	      unresolved_reloc = FALSE;
 	      if (htab->plt_type == PLT_NEW
@@ -10027,27 +10066,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
   return ret;
 }
 
-/* Finish up dynamic symbol handling.  We set the contents of various
-   dynamic sections here.  */
+/* Write out the PLT relocs and entries for H.  */
 
 static bfd_boolean
-ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
-			       struct bfd_link_info *info,
-			       struct elf_link_hash_entry *h,
-			       Elf_Internal_Sym *sym)
+write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
 {
-  struct ppc_elf_link_hash_table *htab;
+  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
   struct plt_entry *ent;
   bfd_boolean doneone;
 
-#ifdef DEBUG
-  fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
-	   h->root.root.string);
-#endif
-
-  htab = ppc_elf_hash_table (info);
-  BFD_ASSERT (htab->elf.dynobj != NULL);
-
   doneone = FALSE;
   for (ent = h->plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.offset != (bfd_vma) -1)
@@ -10090,10 +10118,10 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		/* Fill in the .plt on VxWorks.  */
 		if (bfd_link_pic (info))
 		  {
-		    bfd_put_32 (output_bfd,
+		    bfd_put_32 (info->output_bfd,
 				plt_entry[0] | PPC_HA (got_offset),
 				htab->elf.splt->contents + ent->plt.offset + 0);
-		    bfd_put_32 (output_bfd,
+		    bfd_put_32 (info->output_bfd,
 				plt_entry[1] | PPC_LO (got_offset),
 				htab->elf.splt->contents + ent->plt.offset + 4);
 		  }
@@ -10101,17 +10129,17 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		  {
 		    bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
 
-		    bfd_put_32 (output_bfd,
+		    bfd_put_32 (info->output_bfd,
 				plt_entry[0] | PPC_HA (got_loc),
 				htab->elf.splt->contents + ent->plt.offset + 0);
-		    bfd_put_32 (output_bfd,
+		    bfd_put_32 (info->output_bfd,
 				plt_entry[1] | PPC_LO (got_loc),
 				htab->elf.splt->contents + ent->plt.offset + 4);
 		  }
 
-		bfd_put_32 (output_bfd, plt_entry[2],
+		bfd_put_32 (info->output_bfd, plt_entry[2],
 			    htab->elf.splt->contents + ent->plt.offset + 8);
-		bfd_put_32 (output_bfd, plt_entry[3],
+		bfd_put_32 (info->output_bfd, plt_entry[3],
 			    htab->elf.splt->contents + ent->plt.offset + 12);
 
 		/* This instruction is an immediate load.  The value loaded is
@@ -10120,7 +10148,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		   low-order 16 bits of the load instruction.  */
 		/* NOTE: It appears that this is now an index rather than a
 		   prescaled offset.  */
-		bfd_put_32 (output_bfd,
+		bfd_put_32 (info->output_bfd,
 			    plt_entry[4] | reloc_index,
 			    htab->elf.splt->contents + ent->plt.offset + 16);
 		/* This instruction is a PC-relative branch whose target is
@@ -10129,21 +10157,22 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		   The address is encoded in bits 6-29, inclusive.  The value
 		   stored is right-shifted by two bits, permitting a 26-bit
 		   offset.  */
-		bfd_put_32 (output_bfd,
+		bfd_put_32 (info->output_bfd,
 			    (plt_entry[5]
 			     | (-(ent->plt.offset + 20) & 0x03fffffc)),
 			    htab->elf.splt->contents + ent->plt.offset + 20);
-		bfd_put_32 (output_bfd, plt_entry[6],
+		bfd_put_32 (info->output_bfd, plt_entry[6],
 			    htab->elf.splt->contents + ent->plt.offset + 24);
-		bfd_put_32 (output_bfd, plt_entry[7],
+		bfd_put_32 (info->output_bfd, plt_entry[7],
 			    htab->elf.splt->contents + ent->plt.offset + 28);
 
 		/* Fill in the GOT entry corresponding to this PLT slot with
 		   the address immediately after the "bctr" instruction
 		   in this PLT entry.  */
-		bfd_put_32 (output_bfd, (htab->elf.splt->output_section->vma
-					 + htab->elf.splt->output_offset
-					 + ent->plt.offset + 16),
+		bfd_put_32 (info->output_bfd,
+			    (htab->elf.splt->output_section->vma
+			     + htab->elf.splt->output_offset
+			     + ent->plt.offset + 16),
 			    htab->elf.sgotplt->contents + got_offset);
 
 		if (!bfd_link_pic (info))
@@ -10161,7 +10190,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
 						R_PPC_ADDR16_HA);
 		    rela.r_addend = got_offset;
-		    bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+		    bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
 		    loc += sizeof (Elf32_External_Rela);
 
 		    /* Provide the @l relocation for the second instruction.  */
@@ -10171,7 +10200,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
 						R_PPC_ADDR16_LO);
 		    rela.r_addend = got_offset;
-		    bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+		    bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
 		    loc += sizeof (Elf32_External_Rela);
 
 		    /* Provide a relocation for the GOT entry corresponding to this
@@ -10182,7 +10211,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		    rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
 						R_PPC_ADDR32);
 		    rela.r_addend = ent->plt.offset + 16;
-		    bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+		    bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
 		  }
 
 		/* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT.
@@ -10217,7 +10246,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		    bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
 				   + htab->glink->output_section->vma
 				   + htab->glink->output_offset);
-		    bfd_put_32 (output_bfd, val,
+		    bfd_put_32 (info->output_bfd, val,
 				splt->contents + ent->plt.offset);
 		  }
 	      }
@@ -10252,44 +10281,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 		if (h->type == STT_GNU_IFUNC && is_static_defined (h))
 		  htab->maybe_local_ifunc_resolver = 1;
 	      }
-	    bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-
-	    if (!h->def_regular)
-	      {
-		/* Mark the symbol as undefined, rather than as
-		   defined in the .plt section.  Leave the value if
-		   there were any relocations where pointer equality
-		   matters (this is a clue for the dynamic linker, to
-		   make function pointer comparisons work between an
-		   application and shared library), otherwise set it
-		   to zero.  */
-		sym->st_shndx = SHN_UNDEF;
-		if (!h->pointer_equality_needed)
-		  sym->st_value = 0;
-		else if (!h->ref_regular_nonweak)
-		  {
-		    /* This breaks function pointer comparisons, but
-		       that is better than breaking tests for a NULL
-		       function pointer.  */
-		    sym->st_value = 0;
-		  }
-	      }
-	    else if (h->type == STT_GNU_IFUNC
-		     && !bfd_link_pic (info))
-	      {
-		/* Set the value of ifunc symbols in a non-pie
-		   executable to the glink entry.  This is to avoid
-		   text relocations.  We can't do this for ifunc in
-		   allocate_dynrelocs, as we do for normal dynamic
-		   function symbols with plt entries, because we need
-		   to keep the original value around for the ifunc
-		   relocation.  */
-		sym->st_shndx = (_bfd_elf_section_from_bfd_section
-				 (output_bfd, htab->glink->output_section));
-		sym->st_value = (ent->glink_offset
-				 + htab->glink->output_offset
-				 + htab->glink->output_section->vma);
-	      }
+	    bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
 	    doneone = TRUE;
 	  }
 
@@ -10298,14 +10290,14 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 	    || h->dynindx == -1)
 	  {
 	    unsigned char *p;
-	    asection *splt = htab->elf.splt;
+	    asection *plt = htab->elf.splt;
 
 	    if (!htab->elf.dynamic_sections_created
 		|| h->dynindx == -1)
-	      splt = htab->elf.iplt;
+	      plt = htab->elf.iplt;
 
 	    p = (unsigned char *) htab->glink->contents + ent->glink_offset;
-	    write_glink_stub (h, ent, splt, p, info);
+	    write_glink_stub (h, ent, plt, p, info);
 
 	    if (!bfd_link_pic (info))
 	      /* We only need one non-PIC glink stub.  */
@@ -10314,6 +10306,165 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 	else
 	  break;
       }
+  return TRUE;
+}
+
+/* Finish up PLT handling.  */
+
+bfd_boolean
+ppc_finish_symbols (struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  bfd *ibfd;
+
+  if (!htab)
+    return TRUE;
+
+  elf_link_hash_traverse (&htab->elf, write_global_sym_plt, info);
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      bfd_vma *local_got, *end_local_got;
+      struct plt_entry **local_plt, **lplt, **end_local_plt;
+      Elf_Internal_Shdr *symtab_hdr;
+      bfd_size_type locsymcount;
+      Elf_Internal_Sym *local_syms = NULL;
+      struct plt_entry *ent;
+
+      if (!is_ppc_elf (ibfd))
+	continue;
+
+      local_got = elf_local_got_offsets (ibfd);
+      if (!local_got)
+	continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_local_got = local_got + locsymcount;
+      local_plt = (struct plt_entry **) end_local_got;
+      end_local_plt = local_plt + locsymcount;
+      for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+	for (ent = *lplt; ent != NULL; ent = ent->next)
+	  {
+	    if (ent->plt.offset != (bfd_vma) -1)
+	      {
+		Elf_Internal_Sym *sym;
+		asection *sym_sec;
+		asection *plt, *relplt;
+		bfd_byte *loc;
+		bfd_vma val;
+		Elf_Internal_Rela rela;
+
+		if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+				lplt - local_plt, ibfd))
+		  {
+		    if (local_syms != NULL
+			&& symtab_hdr->contents != (unsigned char *) local_syms)
+		      free (local_syms);
+		    return FALSE;
+		  }
+
+		val = sym->st_value;
+		if (sym_sec != NULL && sym_sec->output_section != NULL)
+		  val += sym_sec->output_offset + sym_sec->output_section->vma;
+
+		BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
+
+		htab->local_ifunc_resolver = 1;
+		plt = htab->elf.iplt;
+		relplt = htab->elf.irelplt;
+
+		rela.r_offset = (ent->plt.offset
+				 + plt->output_offset
+				 + plt->output_section->vma);
+		rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+		rela.r_addend = val;
+		loc = relplt->contents + (relplt->reloc_count++
+					  * sizeof (Elf32_External_Rela));
+		bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
+	      }
+	    if ((ent->glink_offset & 1) == 0)
+	      {
+		unsigned char *p = ((unsigned char *) htab->glink->contents
+				    + ent->glink_offset);
+
+		write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
+		ent->glink_offset |= 1;
+	      }
+	  }
+
+      if (local_syms != NULL
+	  && symtab_hdr->contents != (unsigned char *) local_syms)
+	{
+	  if (!info->keep_memory)
+	    free (local_syms);
+	  else
+	    symtab_hdr->contents = (unsigned char *) local_syms;
+	}
+    }
+  return TRUE;
+}
+
+/* Finish up dynamic symbol handling.  We set the contents of various
+   dynamic sections here.  */
+
+static bfd_boolean
+ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
+			       struct bfd_link_info *info,
+			       struct elf_link_hash_entry *h,
+			       Elf_Internal_Sym *sym)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  struct plt_entry *ent;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
+	   h->root.root.string);
+#endif
+
+  if (!h->def_regular
+      || (h->type == STT_GNU_IFUNC && !bfd_link_pic (info)))
+    for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+      if (ent->plt.offset != (bfd_vma) -1)
+	{
+	  if (!h->def_regular)
+	    {
+	      /* Mark the symbol as undefined, rather than as
+		 defined in the .plt section.  Leave the value if
+		 there were any relocations where pointer equality
+		 matters (this is a clue for the dynamic linker, to
+		 make function pointer comparisons work between an
+		 application and shared library), otherwise set it
+		 to zero.  */
+	      sym->st_shndx = SHN_UNDEF;
+	      if (!h->pointer_equality_needed)
+		sym->st_value = 0;
+	      else if (!h->ref_regular_nonweak)
+		{
+		  /* This breaks function pointer comparisons, but
+		     that is better than breaking tests for a NULL
+		     function pointer.  */
+		  sym->st_value = 0;
+		}
+	    }
+	  else
+	    {
+	      /* Set the value of ifunc symbols in a non-pie
+		 executable to the glink entry.  This is to avoid
+		 text relocations.  We can't do this for ifunc in
+		 allocate_dynrelocs, as we do for normal dynamic
+		 function symbols with plt entries, because we need
+		 to keep the original value around for the ifunc
+		 relocation.  */
+	      sym->st_shndx
+		= (_bfd_elf_section_from_bfd_section
+		   (info->output_bfd, htab->glink->output_section));
+	      sym->st_value = (ent->glink_offset
+			       + htab->glink->output_offset
+			       + htab->glink->output_section->vma);
+	    }
+	  break;
+	}
 
   if (h->needs_copy)
     {
diff --git a/bfd/elf32-ppc.h b/bfd/elf32-ppc.h
index f56d027..265859b 100644
--- a/bfd/elf32-ppc.h
+++ b/bfd/elf32-ppc.h
@@ -63,6 +63,6 @@ int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *);
 asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *);
 bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *);
 void ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *);
-extern bfd_boolean ppc_elf_modify_segment_map (bfd *,
-			   struct bfd_link_info * ATTRIBUTE_UNUSED);
+extern bfd_boolean ppc_elf_modify_segment_map (bfd *, struct bfd_link_info *);
 extern bfd_boolean ppc_elf_section_processing (bfd *, Elf_Internal_Shdr *);
+extern bfd_boolean ppc_finish_symbols (struct bfd_link_info *);
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 835baec..8291db8 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -11158,29 +11158,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       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;
-	  if (htab->opd_abi)
-	    rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
-	  else
-	    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);
-
-	  rl = (htab->elf.irelplt->contents
-		+ (htab->elf.irelplt->reloc_count++
-		   * sizeof (Elf64_External_Rela)));
-	  bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
-	  stub_entry->plt_ent->plt.offset |= 1;
-	  htab->local_ifunc_resolver = 1;
-	}
-
       off = (dest
 	     - elf_gp (info->output_bfd)
 	     - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
@@ -13016,34 +12993,84 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
 }
 
 /* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to
-   write out any global entry stubs.  */
+   write out any global entry stubs, and PLT relocations.  */
 
 static bfd_boolean
-build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
+build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
-  struct plt_entry *pent;
+  struct plt_entry *ent;
   asection *s;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
+  info = inf;
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
+  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+    if (ent->plt.offset != (bfd_vma) -1)
+      {
+	/* This symbol has an entry in the procedure linkage
+	   table.  Set it up.  */
+	Elf_Internal_Rela rela;
+	bfd_byte *loc;
+
+	if (!htab->elf.dynamic_sections_created
+	    || h->dynindx == -1)
+	  {
+	    if (!(h->def_regular
+		  && (h->root.type == bfd_link_hash_defined
+		      || h->root.type == bfd_link_hash_defweak)))
+	      continue;
+	    rela.r_offset = (htab->elf.iplt->output_section->vma
+			     + htab->elf.iplt->output_offset
+			     + ent->plt.offset);
+	    if (htab->opd_abi)
+	      rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+	    else
+	      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);
+	    loc = (htab->elf.irelplt->contents
+		   + (htab->elf.irelplt->reloc_count++
+		      * sizeof (Elf64_External_Rela)));
+	    htab->local_ifunc_resolver = 1;
+	  }
+	else
+	  {
+	    rela.r_offset = (htab->elf.splt->output_section->vma
+			     + htab->elf.splt->output_offset
+			     + ent->plt.offset);
+	    rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
+	    rela.r_addend = ent->addend;
+	    loc = (htab->elf.srelplt->contents
+		   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
+		      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
+	    if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+	      htab->maybe_local_ifunc_resolver = 1;
+	  }
+	bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+      }
+
   if (!h->pointer_equality_needed)
     return TRUE;
 
   if (h->def_regular)
     return TRUE;
 
-  info = inf;
-  htab = ppc_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-
   s = htab->global_entry;
-  for (pent = h->plt.plist; pent != NULL; pent = pent->next)
-    if (pent->plt.offset != (bfd_vma) -1
-	&& pent->addend == 0)
+  if (s == NULL || s->size == 0)
+    return TRUE;
+
+  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+    if (ent->plt.offset != (bfd_vma) -1
+	&& ent->addend == 0)
       {
 	bfd_byte *p;
 	asection *plt;
@@ -13054,7 +13081,7 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
 	if (!htab->elf.dynamic_sections_created
 	    || h->dynindx == -1)
 	  plt = htab->elf.iplt;
-	off = pent->plt.offset + plt->output_offset + plt->output_section->vma;
+	off = ent->plt.offset + plt->output_offset + plt->output_section->vma;
 	off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
 
 	if (off + 0x80008000 > 0xffffffff || (off & 3) != 0)
@@ -13108,6 +13135,91 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
+/* Write PLT relocs for locals.  */
+
+static bfd_boolean
+write_plt_relocs_for_local_syms (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      struct got_entry **lgot_ents, **end_lgot_ents;
+      struct plt_entry **local_plt, **lplt, **end_local_plt;
+      Elf_Internal_Shdr *symtab_hdr;
+      bfd_size_type locsymcount;
+      Elf_Internal_Sym *local_syms = NULL;
+      struct plt_entry *ent;
+
+      if (!is_ppc64_elf (ibfd))
+	continue;
+
+      lgot_ents = elf_local_got_ents (ibfd);
+      if (!lgot_ents)
+	continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_lgot_ents = lgot_ents + locsymcount;
+      local_plt = (struct plt_entry **) end_lgot_ents;
+      end_local_plt = local_plt + locsymcount;
+      for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+	for (ent = *lplt; ent != NULL; ent = ent->next)
+	  if (ent->plt.offset != (bfd_vma) -1)
+	    {
+	      Elf_Internal_Sym *sym;
+	      asection *sym_sec;
+	      asection *plt, *relplt;
+	      bfd_byte *loc;
+	      bfd_vma val;
+	      Elf_Internal_Rela rela;
+
+	      if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+			      lplt - local_plt, ibfd))
+		{
+		  if (local_syms != NULL
+		      && symtab_hdr->contents != (unsigned char *) local_syms)
+		    free (local_syms);
+		  return FALSE;
+		}
+
+	      val = sym->st_value + ent->addend;
+	      val += PPC64_LOCAL_ENTRY_OFFSET (sym->st_other);
+	      if (sym_sec != NULL && sym_sec->output_section != NULL)
+		val += sym_sec->output_offset + sym_sec->output_section->vma;
+
+	      BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
+
+	      htab->local_ifunc_resolver = 1;
+	      plt = htab->elf.iplt;
+	      relplt = htab->elf.irelplt;
+
+	      rela.r_offset = (ent->plt.offset
+			       + plt->output_offset
+			       + plt->output_section->vma);
+	      if (htab->opd_abi)
+		rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+	      else
+		rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+	      rela.r_addend = val;
+	      loc = relplt->contents + (relplt->reloc_count++
+					* sizeof (Elf64_External_Rela));
+	      bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+	    }
+
+      if (local_syms != NULL
+	  && symtab_hdr->contents != (unsigned char *) local_syms)
+	{
+	  if (!info->keep_memory)
+	    free (local_syms);
+	  else
+	    symtab_hdr->contents = (unsigned char *) local_syms;
+	}
+    }
+  return TRUE;
+}
+
 /* Build all the stubs associated with the current output file.
    The stubs are kept in a hash table attached to the main linker
    hash table.  This function is called via gldelf64ppc_finish.  */
@@ -13262,9 +13374,11 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
 	}
     }
 
-  /* Build .glink global entry stubs.  */
-  if (htab->global_entry != NULL && htab->global_entry->size != 0)
-    elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
+  /* Build .glink global entry stubs, and PLT relocs for globals.  */
+  elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info);
+
+  if (!write_plt_relocs_for_local_syms (info))
+    return FALSE;
 
   if (htab->brlt != NULL && htab->brlt->size != 0)
     {
@@ -15488,85 +15602,41 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
 {
   struct ppc_link_hash_table *htab;
   struct plt_entry *ent;
-  Elf_Internal_Rela rela;
-  bfd_byte *loc;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
-  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
-    if (ent->plt.offset != (bfd_vma) -1)
-      {
-	/* This symbol has an entry in the procedure linkage
-	   table.  Set it up.  */
-	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_offset = (htab->elf.iplt->output_section->vma
-			     + htab->elf.iplt->output_offset
-			     + ent->plt.offset);
-	    if (htab->opd_abi)
-	      rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
-	    else
-	      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);
-	    loc = (htab->elf.irelplt->contents
-		   + (htab->elf.irelplt->reloc_count++
-		      * sizeof (Elf64_External_Rela)));
-	    htab->local_ifunc_resolver = 1;
-	  }
-	else
-	  {
-	    rela.r_offset = (htab->elf.splt->output_section->vma
-			     + htab->elf.splt->output_offset
-			     + ent->plt.offset);
-	    rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
-	    rela.r_addend = ent->addend;
-	    loc = (htab->elf.srelplt->contents
-		   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
-		      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
-	    if (h->type == STT_GNU_IFUNC && is_static_defined (h))
-	      htab->maybe_local_ifunc_resolver = 1;
-	  }
-	bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
-
-	if (!htab->opd_abi)
-	  {
-	    if (!h->def_regular)
-	      {
-		/* Mark the symbol as undefined, rather than as
-		   defined in glink.  Leave the value if there were
-		   any relocations where pointer equality matters
-		   (this is a clue for the dynamic linker, to make
-		   function pointer comparisons work between an
-		   application and shared library), otherwise set it
-		   to zero.  */
-		sym->st_shndx = SHN_UNDEF;
-		if (!h->pointer_equality_needed)
-		  sym->st_value = 0;
-		else if (!h->ref_regular_nonweak)
-		  {
-		    /* This breaks function pointer comparisons, but
-		       that is better than breaking tests for a NULL
-		       function pointer.  */
-		    sym->st_value = 0;
-		  }
-	      }
-	  }
-      }
+  if (!htab->opd_abi && !h->def_regular)
+    for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+      if (ent->plt.offset != (bfd_vma) -1)
+	{
+	  /* Mark the symbol as undefined, rather than as
+	     defined in glink.  Leave the value if there were
+	     any relocations where pointer equality matters
+	     (this is a clue for the dynamic linker, to make
+	     function pointer comparisons work between an
+	     application and shared library), otherwise set it
+	     to zero.  */
+	  sym->st_shndx = SHN_UNDEF;
+	  if (!h->pointer_equality_needed)
+	    sym->st_value = 0;
+	  else if (!h->ref_regular_nonweak)
+	    {
+	      /* This breaks function pointer comparisons, but
+		 that is better than breaking tests for a NULL
+		 function pointer.  */
+	      sym->st_value = 0;
+	    }
+	  break;
+	}
 
   if (h->needs_copy)
     {
       /* This symbol needs a copy reloc.  Set it up.  */
+      Elf_Internal_Rela rela;
       asection *srel;
+      bfd_byte *loc;
 
       if (h->dynindx == -1
 	  || (h->root.type != bfd_link_hash_defined
diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em
index 3c335b7..05a2894 100644
--- a/ld/emultempl/ppc32elf.em
+++ b/ld/emultempl/ppc32elf.em
@@ -212,6 +212,8 @@ ppc_finish (void)
 {
   if (params.ppc476_workaround)
     lang_for_each_statement (no_zero_padding);
+  if (!ppc_finish_symbols (&link_info))
+    einfo (_("%X%P: ppc_finish_symbols problem %E\n"));
   finish_default ();
 }
 

-- 
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]