Fix BLX(1) for Thumb
authorNick Clifton <nickc@redhat.com>
Tue, 6 Mar 2001 22:33:47 +0000 (22:33 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 6 Mar 2001 22:33:47 +0000 (22:33 +0000)
bfd/ChangeLog
bfd/coff-arm.c
bfd/elf32-arm.h
gas/ChangeLog
gas/config/tc-arm.c
opcodes/ChangeLog
opcodes/arm-dis.c
sim/arm/ChangeLog
sim/arm/thumbemu.c

index 1e037b0..32794be 100644 (file)
@@ -1,5 +1,13 @@
 2001-03-06  Nick Clifton  <nickc@redhat.com>
 
+       * elf32-arm.h (elf32_arm_final_link_relocate): Clear bit zero
+       of offset in BLX(1) instruction.
+       * coff-arm.c (coff_arm_relocate_section): Clear bit zero of
+       offset in BLX(1) instruction.
+        Fix formatting.
+
+2001-03-06  Nick Clifton  <nickc@redhat.com>
+
        * coff-arm.c (coff_arm_reloc_type_lookup): Add
        BFD_RELOC_THUMB_PCREL_BLX.
 
index 3431567..ad4813f 100644 (file)
@@ -1588,18 +1588,18 @@ coff_arm_relocate_section (output_bfd, info, input_bfd, input_section,
 
              BFD_ASSERT (size == 4);
 
-              /* howto->pc_relative should be TRUE for type 14 BRANCH23 */
+              /* howto->pc_relative should be TRUE for type 14 BRANCH23 */
               relocation -= (input_section->output_section->vma
                              + input_section->output_offset);
 
-              /* howto->pcrel_offset should be TRUE for type 14 BRANCH23 */
+              /* howto->pcrel_offset should be TRUE for type 14 BRANCH23 */
               relocation -= address;
 
              /* No need to negate the relocation with BRANCH23.  */
              /* howto->complain_on_overflow == complain_overflow_signed for BRANCH23.  */
              /* howto->rightshift == 1 */
-             /* Drop unwanted bits from the value we are relocating to.  */
 
+             /* Drop unwanted bits from the value we are relocating to.  */
              check = relocation >> howto->rightshift;
 
              /* If this is a signed value, the rightshift just dropped
@@ -1613,13 +1613,9 @@ coff_arm_relocate_section (output_bfd, info, input_bfd, input_section,
 
              /* Get the value from the object file.  */
              if (bfd_big_endian (input_bfd))
-               {
-                 add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1);
-               }
+               add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1);
              else
-               {
-                 add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15));
-               }
+               add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15));
 
              /* Get the value from the object file with an appropriate sign.
                 The expression involving howto->src_mask isolates the upper
@@ -1629,18 +1625,16 @@ coff_arm_relocate_section (output_bfd, info, input_bfd, input_section,
                 can not get the upper bit, but that does not matter since
                 signed_add needs no adjustment to become negative in that
                 case.  */
-
              signed_add = add;
 
              if ((add & (((~ src_mask) >> 1) & src_mask)) != 0)
                signed_add -= (((~ src_mask) >> 1) & src_mask) << 1;
 
+             /* howto->bitpos == 0 */
              /* Add the value from the object file, shifted so that it is a
                 straight number.  */
-             /* howto->bitpos == 0 */
-
              signed_check += signed_add;
-             relocation += signed_add;
+             relocation   += signed_add;
 
              BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed);
 
@@ -1649,21 +1643,26 @@ coff_arm_relocate_section (output_bfd, info, input_bfd, input_section,
                  || signed_check < reloc_signed_min)
                overflow = true;
 
-             /* Put RELOCATION into the correct bits:  */
-
+             /* For the BLX(1) instruction remove bit 0 of the adjusted offset.
+                Bit 0 can only be set if the upper insn is at a half-word boundary,
+                since the destination address, an ARM instruction, must always be
+                on a word boundary.  The semantics of the BLX (1) instruction,
+                however, are that bit 0 in the offset must always be 0, and the
+                corresponding bit 1 in the target address will be set from bit
+                1 of the source address.  */
+             if ((x & 0x18000000) == 0x08000000)
+               relocation &= ~0x2;
+
+             /* Put the relocation into the correct bits.  */
              if (bfd_big_endian (input_bfd))
-               {
-                 relocation = (((relocation & 0xffe) >> 1)  | ((relocation << 4) & 0x07ff0000));
-               }
+               relocation = (((relocation & 0xffe) >> 1)  | ((relocation << 4) & 0x07ff0000));
              else
-               {
-                 relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
-               }
+               relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
 
-             /* Add RELOCATION to the correct bits of X:  */
+             /* Add the relocation to the correct bits of X.  */
              x = ((x & ~howto->dst_mask) | relocation);
 
-             /* Put the relocated value back in the object file:  */
+             /* Put the relocated value back in the object file.  */
              bfd_put_32 (input_bfd, x, location);
 
              rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok;
index 6b56797..b64df9a 100644 (file)
@@ -1434,6 +1434,17 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
        upper_insn = (upper_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 12) & 0x7ff);
        lower_insn = (lower_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 1) & 0x7ff);
 
+       if (r_type == R_ARM_THM_XPC22
+           && ((lower_insn & 0x1800) == 0x0800))
+         /* Remove bit zero of the adjusted offset.  Bit zero can only be
+            set if the upper insn is at a half-word boundary, since the
+            destination address, an ARM instruction, must always be on a
+            word boundary.  The semantics of the BLX (1) instruction, however,
+            are that bit zero in the offset must always be zero, and the
+            corresponding bit one in the target address will be set from bit
+            one of the source address.  */
+         lower_insn &= ~1;
+       
        /* Put the relocated value back in the object file:  */
        bfd_put_16 (input_bfd, upper_insn, hit_data);
        bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
index 503102a..9654744 100644 (file)
@@ -1,3 +1,8 @@
+2001-03-06  Nick Clifton  <nickc@redhat.com>
+
+       * config/tc-arm.c (md_apply_fix3): Clear bit zero of offset in
+       BLX(1) instruction.
+
 2001-03-06  Igor Shevlyakov  <igor@windriver.com>
 
        * config/tc-m68k.c : Add 5407 to archs[] table.
index 514dba7..ebb7b97 100644 (file)
@@ -7149,6 +7149,15 @@ md_apply_fix3 (fixP, val, seg)
 
        newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
        newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
+       if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
+         /* Remove bit zero of the adjusted offset.  Bit zero can only be
+            set if the upper insn is at a half-word boundary, since the
+            destination address, an ARM instruction, must always be on a
+            word boundary.  The semantics of the BLX (1) instruction, however,
+            are that bit zero in the offset must always be zero, and the
+            corresponding bit one in the target address will be set from bit
+            one of the source address.  */
+         newval2 &= ~1;
        md_number_to_chars (buf, newval, THUMB_SIZE);
        md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
       }
index 5b21a5c..3677f2e 100644 (file)
@@ -1,3 +1,9 @@
+2001-03-06  Nick Clifton  <nickc@redhat.com>
+
+       * arm-dis.c (print_insn_thumb): Compute destination address
+        of BLX(1) instruction by taking bit 1 from PC and not from bit
+        0 of the offset.
+
 2001-03-06  Igor Shevlyakov  <igor@windriver.com>
 
        * m68k-dis.c (print_insn_m68k): Recognize Coldfire CPUs
index 686b18a..0681758 100644 (file)
@@ -668,15 +668,32 @@ print_insn_thumb (pc, info, given)
           /* Special processing for Thumb 2 instruction BL sequence:  */
           if (!*c) /* Check for empty (not NULL) assembler string.  */
             {
+             long offset;
+             
              info->bytes_per_chunk = 4;
              info->bytes_per_line  = 4;
+
+             offset = BDISP23 (given);
              
              if ((given & 0x10000000) == 0)
-                 func (stream, "blx\t");
+               {
+                 func (stream, "blx\t");
+
+                 /* The spec says that bit 1 of the branch's destination
+                    address comes from bit 1 of the instruction's
+                    address and not from the offset in the instruction.  */
+                 if (offset & 0x1)
+                   {
+                     /* func (stream, "*malformed!* "); */
+                     offset &= ~ 0x1;
+                   }
+
+                 offset |= ((pc & 0x2) >> 1);
+               }
              else
-                func (stream, "bl\t");
-               
-              info->print_address_func (BDISP23 (given) * 2 + pc + 4, info);
+               func (stream, "bl\t");
+
+             info->print_address_func (offset * 2 + pc + 4, info);
               return 4;
             }
           else
index fd11ec1..d3d5b1c 100644 (file)
@@ -1,3 +1,9 @@
+2001-03-06  Nick Clifton  <nickc@redhat.com>
+
+       * thumbemu.c (ARMul_ThumbDecode): Delete label bo_blx2.
+        Compute destination address of BLX(1) instruction by
+        taking bit 1 from PC and not from bit 0 of the offset.        
+
 2001-02-27  Nick Clifton  <nickc@redhat.com>
 
        * armvirt.c (GetWord): Add new parameter - check - to enable or
index 3351c2f..4f00733 100644 (file)
@@ -481,7 +481,6 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
            }
          /* Drop through.  */
          
-       do_blx2:                        /* BLX instruction 2 */
          /* Format 19 */
          /* There is no single ARM instruction equivalent for this
             instruction. Also, it should only ever be matched with the
@@ -514,17 +513,31 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
          |((tinstr & (1 << 10)) ? 0xFF800000 : 0));
       valid = t_branch;                /* in-case we don't have the 2nd half */
       tinstr = next_instr;     /* move the instruction down */
+      pc += 2;                 /* point the pc at the 2nd half */
       if (((tinstr & 0xF800) >> 11) != 31)
        {
          if (((tinstr & 0xF800) >> 11) == 29)
            {
-             pc += 2;
-             goto do_blx2;
+             ARMword tmp = (pc + 2);
+
+             /* Bit one of the destination address comes from bit one of the
+                address of the first (H == 10) half of the instruction, not
+                from the offset in the instruction.  */
+             state->Reg[15] = ((state->Reg[14]
+                                + ((tinstr & 0x07FE) << 1)
+                                + ((pc - 2) & 2))
+                               & 0xFFFFFFFC);
+             CLEART;
+             state->Reg[14] = (tmp | 1);
+             valid = t_branch;
+             FLUSHPIPE;
            }
-         break;                /* exit, since not correct instruction */
+         else
+           /* Exit, since not correct instruction. */
+           pc -= 2;
+         break;
        }
       /* else we fall through to process the second half of the BL */
-      pc += 2;                 /* point the pc at the 2nd half */
     case 31:                   /* BL instruction 2 */
       /* Format 19 */
       /* There is no single ARM instruction equivalent for this