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]

ppc476 workaround for ld -r fixes


This fixes the glaring error that the ppc476 workaround wasn't
actually enabled for ld -r, and adjusts relocations to match moved
code.

bfd/
	* elf32-ppc.c (ppc_elf_relocate_section): Move relocs on insns
	patched for ppc476 workaround.  Reapply branch taken/not taken
	relocs.
ld/
	* emultempl/ppc32elf.em (ppc_after_open_output): Really enable
	ppc476 workaround for ld -r.

diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index d8e6108..1c8724f 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -9230,13 +9230,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	     the word alone.  */
 	  is_data = FALSE;
 	  lo = relocs;
-	  hi = lo + input_section->reloc_count;
+	  hi = relend;
+	  rel = NULL;
 	  while (lo < hi)
 	    {
 	      rel = lo + (hi - lo) / 2;
 	      if (rel->r_offset < offset)
 		lo = rel + 1;
-	      else if (rel->r_offset > offset)
+	      else if (rel->r_offset > offset + 3)
 		hi = rel;
 	      else
 		{
@@ -9285,12 +9286,53 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	  patch_addr = (patch_addr + 15) & -16;
 	  patch_off = patch_addr - start_addr;
 	  bfd_put_32 (input_bfd, B + patch_off - offset, contents + offset);
+
+	  if (rel != NULL
+	      && rel->r_offset >= offset
+	      && rel->r_offset < offset + 4)
+	    {
+	      /* If the insn we are patching had a reloc, adjust the
+		 reloc r_offset so that the reloc applies to the moved
+		 location.  This matters for -r and --emit-relocs.  */
+	      if (rel + 1 != relend)
+		{
+		  Elf_Internal_Rela tmp = *rel;
+
+		  /* Keep the relocs sorted by r_offset.  */
+		  memmove (rel, rel + 1, (relend - (rel + 1)) * sizeof (*rel));
+		  relend[-1] = tmp;
+		}
+	      relend[-1].r_offset += patch_off - offset;
+	    }
+	  else
+	    rel = NULL;
+
 	  if ((insn & (0x3f << 26)) == (16u << 26) /* bc */
 	      && (insn & 2) == 0 /* relative */)
 	    {
 	      bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
 
 	      delta += offset - patch_off;
+	      if (info->relocatable && rel != NULL)
+		delta = 0;
+	      if (!info->relocatable && rel != NULL)
+		{
+		  enum elf_ppc_reloc_type r_type;
+
+		  r_type = ELF32_R_TYPE (relend[-1].r_info);
+		  if (r_type == R_PPC_REL14_BRTAKEN)
+		    insn |= BRANCH_PREDICT_BIT;
+		  else if (r_type == R_PPC_REL14_BRNTAKEN)
+		    insn &= ~BRANCH_PREDICT_BIT;
+		  else
+		    BFD_ASSERT (r_type == R_PPC_REL14);
+
+		  if ((r_type == R_PPC_REL14_BRTAKEN
+		       || r_type == R_PPC_REL14_BRNTAKEN)
+		      && delta + 0x8000 < 0x10000
+		      && (bfd_signed_vma) delta < 0)
+		    insn ^= BRANCH_PREDICT_BIT;
+		}
 	      if (delta + 0x8000 < 0x10000)
 		{
 		  bfd_put_32 (input_bfd,
@@ -9304,6 +9346,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
 		}
 	      else
 		{
+		  if (rel != NULL)
+		    {
+		      unsigned int r_sym = ELF32_R_SYM (relend[-1].r_info);
+
+		      relend[-1].r_offset += 8;
+		      relend[-1].r_info = ELF32_R_INFO (r_sym, R_PPC_REL24);
+		    }
 		  bfd_put_32 (input_bfd,
 			      (insn & ~0xfffc) | 8,
 			      contents + patch_off);
diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em
index 8de230a..f5a3a70 100644
--- a/ld/emultempl/ppc32elf.em
+++ b/ld/emultempl/ppc32elf.em
@@ -51,8 +51,6 @@ ppc_after_open_output (void)
   if (pagesize == 0)
     pagesize = config.commonpagesize;
   params.pagesize_p2 = bfd_log2 (pagesize);
-  if (link_info.relocatable)
-    params.ppc476_workaround = 0;
   ppc_elf_link_params (&link_info, &params);
 }
 

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