This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Fix implementation of BLX(1) instruction for Thumb
- To: binutils at sources dot redhat dot com
- Subject: Fix implementation of BLX(1) instruction for Thumb
- From: Nick Clifton <nickc at redhat dot com>
- Date: 06 Mar 2001 14:32:46 -0800
Hi Guys,
I am applying the following patch to fix the implementation of the
new v5 BLX(1) instruction for the Thumb. The problem was that the
code was assuming that bit 0 of the offset could be set, whereas in
fact the spec says that it must always be zero.
Cheers
Nick
gas/ChangeLog
2001-03-06 Nick Clifton <nickc@redhat.com>
* config/tc-arm.c (md_apply_fix3): Clear bit zero of offset in
BLX(1) instruction.
bfd/ChangeLog
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.
opcodes/ChangeLog
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.
sim/arm/ChangeLog
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.
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src//src/gas/config/tc-arm.c,v
retrieving revision 1.73
diff -p -r1.73 tc-arm.c
*** tc-arm.c 2001/02/12 13:32:25 1.73
--- tc-arm.c 2001/03/06 22:23:40
*************** md_apply_fix3 (fixP, val, seg)
*** 7149,7154 ****
--- 7149,7163 ----
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: bfd/elf32-arm.h
===================================================================
RCS file: /cvs/src//src/bfd/elf32-arm.h,v
retrieving revision 1.44
diff -p -r1.44 elf32-arm.h
*** elf32-arm.h 2001/02/28 10:13:20 1.44
--- elf32-arm.h 2001/03/06 22:23:40
*************** elf32_arm_final_link_relocate (howto, in
*** 1434,1439 ****
--- 1434,1450 ----
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: bfd/coff-arm.c
===================================================================
RCS file: /cvs/src//src/bfd/coff-arm.c,v
retrieving revision 1.24
diff -p -r1.24 coff-arm.c
*** coff-arm.c 2001/03/06 20:27:50 1.24
--- coff-arm.c 2001/03/06 22:23:40
*************** coff_arm_relocate_section (output_bfd, i
*** 1588,1605 ****
BFD_ASSERT (size == 4);
! /* 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 */
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. */
check = relocation >> howto->rightshift;
/* If this is a signed value, the rightshift just dropped
--- 1588,1605 ----
BFD_ASSERT (size == 4);
! /* 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. */
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. */
check = relocation >> howto->rightshift;
/* If this is a signed value, the rightshift just dropped
*************** coff_arm_relocate_section (output_bfd, i
*** 1613,1625 ****
/* Get the value from the object file. */
if (bfd_big_endian (input_bfd))
! {
! add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1);
! }
else
! {
! 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
--- 1613,1621 ----
/* Get the value from the object file. */
if (bfd_big_endian (input_bfd))
! add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1);
else
! 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
*************** coff_arm_relocate_section (output_bfd, i
*** 1629,1646 ****
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;
/* 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;
BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed);
--- 1625,1640 ----
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. */
signed_check += signed_add;
! relocation += signed_add;
BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed);
*************** coff_arm_relocate_section (output_bfd, i
*** 1649,1669 ****
|| signed_check < reloc_signed_min)
overflow = true;
! /* Put RELOCATION into the correct bits: */
if (bfd_big_endian (input_bfd))
! {
! relocation = (((relocation & 0xffe) >> 1) | ((relocation << 4) & 0x07ff0000));
! }
else
! {
! relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
! }
! /* Add RELOCATION to the correct bits of X: */
x = ((x & ~howto->dst_mask) | relocation);
! /* Put the relocated value back in the object file: */
bfd_put_32 (input_bfd, x, location);
rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok;
--- 1643,1668 ----
|| signed_check < reloc_signed_min)
overflow = true;
! /* 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));
else
! relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
! /* Add the relocation to the correct bits of X. */
x = ((x & ~howto->dst_mask) | relocation);
! /* 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: opcodes/arm-dis.c
===================================================================
RCS file: /cvs/src//src/opcodes/arm-dis.c,v
retrieving revision 1.20
diff -p -r1.20 arm-dis.c
*** arm-dis.c 2001/01/09 20:29:48 1.20
--- arm-dis.c 2001/03/06 22:23:40
*************** print_insn_thumb (pc, info, given)
*** 668,682 ****
/* Special processing for Thumb 2 instruction BL sequence: */
if (!*c) /* Check for empty (not NULL) assembler string. */
{
info->bytes_per_chunk = 4;
info->bytes_per_line = 4;
if ((given & 0x10000000) == 0)
! func (stream, "blx\t");
else
! func (stream, "bl\t");
!
! info->print_address_func (BDISP23 (given) * 2 + pc + 4, info);
return 4;
}
else
--- 668,699 ----
/* 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");
!
! /* 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 (offset * 2 + pc + 4, info);
return 4;
}
else
Index: sim/arm/thumbemu.c
===================================================================
RCS file: /cvs/src//src/sim/arm/thumbemu.c,v
retrieving revision 1.2
diff -p -r1.2 thumbemu.c
*** thumbemu.c 2000/11/30 01:55:12 1.2
--- thumbemu.c 2001/03/06 22:23:40
*************** tdstate ARMul_ThumbDecode (state, pc, ti
*** 481,487 ****
}
/* 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
--- 481,486 ----
*************** tdstate ARMul_ThumbDecode (state, pc, ti
*** 514,530 ****
|((tinstr & (1 << 10)) ? 0xFF800000 : 0));
valid = t_branch; /* in-case we don't have the 2nd half */
tinstr = next_instr; /* move the instruction down */
if (((tinstr & 0xF800) >> 11) != 31)
{
if (((tinstr & 0xF800) >> 11) == 29)
{
! pc += 2;
! goto do_blx2;
}
! break; /* exit, since not correct instruction */
}
/* 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
--- 513,543 ----
|((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)
{
! 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;
}
! else
! /* Exit, since not correct instruction. */
! pc -= 2;
! break;
}
/* else we fall through to process the second half of the BL */
case 31: /* BL instruction 2 */
/* Format 19 */
/* There is no single ARM instruction equivalent for this