aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog8
-rw-r--r--bfd/coff-arm.c45
-rw-r--r--bfd/elf32-arm.h11
-rw-r--r--gas/ChangeLog5
-rw-r--r--gas/config/tc-arm.c9
-rw-r--r--opcodes/ChangeLog6
-rw-r--r--opcodes/arm-dis.c25
-rw-r--r--sim/arm/ChangeLog6
-rw-r--r--sim/arm/thumbemu.c23
9 files changed, 106 insertions, 32 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 1e037b0..32794be 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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.
diff --git a/bfd/coff-arm.c b/bfd/coff-arm.c
index 3431567..ad4813f 100644
--- a/bfd/coff-arm.c
+++ b/bfd/coff-arm.c
@@ -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;
diff --git a/bfd/elf32-arm.h b/bfd/elf32-arm.h
index 6b56797..b64df9a 100644
--- a/bfd/elf32-arm.h
+++ b/bfd/elf32-arm.h
@@ -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);
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 503102a..9654744 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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.
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 514dba7..ebb7b97 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -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);
}
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 5b21a5c..3677f2e 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -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
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index 686b18a..0681758 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -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
diff --git a/sim/arm/ChangeLog b/sim/arm/ChangeLog
index fd11ec1..d3d5b1c 100644
--- a/sim/arm/ChangeLog
+++ b/sim/arm/ChangeLog
@@ -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
diff --git a/sim/arm/thumbemu.c b/sim/arm/thumbemu.c
index 3351c2f..4f00733 100644
--- a/sim/arm/thumbemu.c
+++ b/sim/arm/thumbemu.c
@@ -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