* elf64-ppc.c (ppc64_elf_relocate_section): Correct branch
authorAlan Modra <amodra@gmail.com>
Thu, 1 Nov 2001 05:35:10 +0000 (05:35 +0000)
committerAlan Modra <amodra@gmail.com>
Thu, 1 Nov 2001 05:35:10 +0000 (05:35 +0000)
prediction bits.

bfd/ChangeLog
bfd/elf64-ppc.c

index 1a241d9..1efde96 100644 (file)
@@ -1,3 +1,8 @@
+2001-11-01  Alan Modra  <amodra@bigpond.net.au>
+
+       * elf64-ppc.c (ppc64_elf_relocate_section): Correct branch
+       prediction bits.
+
 2001-10-31  Chris Demetriou  <cgd@demetriou.com>
 
        * elf32-mips.c (_bfd_mips_elf_hi16_reloc): Handle PC-relative
index 59ae522..418b386 100644 (file)
@@ -92,9 +92,6 @@ static boolean ppc64_elf_finish_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 
 
-/* Branch prediction bit for branch taken relocs.  */
-#define BRANCH_PREDICT_BIT 0x200000
-
 /* Mask to set RA in memory instructions.  */
 #define RA_REGISTER_MASK 0x001f0000
 
@@ -3161,6 +3158,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        }
 
       /* First handle relocations that tweak non-addend part of insn.  */
+      insn = 0;
       switch (r_type)
        {
        default:
@@ -3169,22 +3167,23 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          /* Branch taken prediction relocations.  */
        case R_PPC64_ADDR14_BRTAKEN:
        case R_PPC64_REL14_BRTAKEN:
-         insn = bfd_get_32 (output_bfd, contents + offset);
-         if ((relocation - offset) & 0x8000)
-           insn &= ~BRANCH_PREDICT_BIT;
-         else
-           insn |= BRANCH_PREDICT_BIT;
-         bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
-         break;
+         insn = 0x01 << 21; /* Set 't' bit, lowest bit of BO field. */
+         /* Fall thru. */
 
-         /* Branch not taken predicition relocations.  */
+         /* Branch not taken prediction relocations.  */
        case R_PPC64_ADDR14_BRNTAKEN:
        case R_PPC64_REL14_BRNTAKEN:
-         insn = bfd_get_32 (output_bfd, contents + offset);
-         if ((relocation - offset) & 0x8000)
-           insn |= BRANCH_PREDICT_BIT;
+         insn |= bfd_get_32 (output_bfd, contents + offset) & ~(0x01 << 21);
+         /* Set 'a' bit.  This is 0b00010 in BO field for branch on CR(BI)
+            insns (BO == 001at or 011at), and 0b01000 for branch on CTR
+            insns (BO == 1a00t or 1a01t).  */
+         if ((insn & (0x14 << 21)) == (0x04 << 21))
+           insn |= 0x02 << 21;
+         else if ((insn & (0x14 << 21)) == (0x10 << 21))
+           insn |= 0x08 << 21;
          else
-           insn &= ~BRANCH_PREDICT_BIT;
+           break;
+
          bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
          break;