This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch] Thumb-2 add PC misassembly
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Thu, 13 Jul 2006 00:54:33 +0100
- Subject: [patch] Thumb-2 add PC misassembly
In Thumb-2 "add reg, pc, #imm" should be assembled to the addw instruction,
not add.w (PC is not a valid source for the latter).
The patch below fixes this. It also uses the addw instruction in other cases
where the immediate is not valid for a normal add.
The same applies for sub.
Tested with cross to arm-none-eabi.
Ok?
2006-07-13 Paul Brook <paul@codesourcery.com>
bfd/
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
* reloc.c: Add BFD_RELOC_ARM_T32_ADD_IMM.
gas/
* tc-arm.c (do_t_add_sub): Use addw/subw when source is PC.
(md_convert_frag): Use correct reloc for add_pc. Use
BFD_RELOC_ARM_T32_ADD_IMM for normal add/sum.
(md_apply_fix): Handle BFD_RELOC_ARM_T32_ADD_IMM.
(arm_force_relocation): Handle BFD_RELOC_ARM_T32_ADD_IMM.
gas/testsuite/
* gas/arm/thumb2_add.d: New test.
* gas/arm/thumb2_add.s: New test.
Index: bfd/bfd-in2.h
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/bfd-in2.h,v
retrieving revision 1.395
diff -u -p -r1.395 bfd-in2.h
--- bfd/bfd-in2.h 19 Jun 2006 13:17:43 -0000 1.395
+++ bfd/bfd-in2.h 12 Jul 2006 23:08:38 -0000
@@ -2966,6 +2966,7 @@ pc-relative or some form of GOT-indirect
BFD_RELOC_ARM_IMMEDIATE,
BFD_RELOC_ARM_ADRL_IMMEDIATE,
BFD_RELOC_ARM_T32_IMMEDIATE,
+ BFD_RELOC_ARM_T32_ADD_IMM,
BFD_RELOC_ARM_T32_IMM12,
BFD_RELOC_ARM_T32_ADD_PC12,
BFD_RELOC_ARM_SHIFT_IMM,
Index: bfd/libbfd.h
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/libbfd.h,v
retrieving revision 1.184
diff -u -p -r1.184 libbfd.h
--- bfd/libbfd.h 19 Jun 2006 13:17:44 -0000 1.184
+++ bfd/libbfd.h 12 Jul 2006 23:08:38 -0000
@@ -1263,6 +1263,7 @@ static const char *const bfd_reloc_code_
"BFD_RELOC_ARM_IMMEDIATE",
"BFD_RELOC_ARM_ADRL_IMMEDIATE",
"BFD_RELOC_ARM_T32_IMMEDIATE",
+ "BFD_RELOC_ARM_T32_ADD_IMM",
"BFD_RELOC_ARM_T32_IMM12",
"BFD_RELOC_ARM_T32_ADD_PC12",
"BFD_RELOC_ARM_SHIFT_IMM",
Index: bfd/reloc.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/reloc.c,v
retrieving revision 1.155
diff -u -p -r1.155 reloc.c
--- bfd/reloc.c 15 Jun 2006 11:03:00 -0000 1.155
+++ bfd/reloc.c 12 Jul 2006 23:08:31 -0000
@@ -2822,6 +2822,8 @@ ENUMX
ENUMX
BFD_RELOC_ARM_T32_IMMEDIATE
ENUMX
+ BFD_RELOC_ARM_T32_ADD_IMM
+ENUMX
BFD_RELOC_ARM_T32_IMM12
ENUMX
BFD_RELOC_ARM_T32_ADD_PC12
Index: gas/config/tc-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/gas/config/tc-arm.c,v
retrieving revision 1.278
diff -u -p -r1.278 tc-arm.c
--- gas/config/tc-arm.c 21 Jun 2006 14:20:24 -0000 1.278
+++ gas/config/tc-arm.c 12 Jul 2006 23:43:25 -0000
@@ -8186,13 +8186,13 @@ do_t_add_sub (void)
narrow = (current_it_mask != 0);
if (!inst.operands[2].isreg)
{
+ int add;
+
+ add = (inst.instruction == T_MNEM_add
+ || inst.instruction == T_MNEM_adds);
opcode = 0;
if (inst.size_req != 4)
{
- int add;
-
- add = (inst.instruction == T_MNEM_add
- || inst.instruction == T_MNEM_adds);
/* Attempt to use a narrow opcode, with relaxation if
appropriate. */
if (Rd == REG_SP && Rs == REG_SP && !flags)
@@ -8222,12 +8222,24 @@ do_t_add_sub (void)
if (inst.size_req == 4
|| (inst.size_req != 2 && !opcode))
{
- /* ??? Convert large immediates to addw/subw. */
- inst.instruction = THUMB_OP32 (inst.instruction);
- inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
+ if (Rs == REG_PC)
+ {
+ /* Always use addw/subw. */
+ inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
+ inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+ }
+ else
+ {
+ inst.instruction = THUMB_OP32 (inst.instruction);
+ inst.instruction = (inst.instruction & 0xe1ffffff)
+ | 0x10000000;
+ if (flags)
+ inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ else
+ inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
+ }
inst.instruction |= inst.operands[0].reg << 8;
inst.instruction |= inst.operands[1].reg << 16;
- inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
}
}
else
@@ -16136,7 +16148,10 @@ md_convert_frag (bfd *abfd, segT asec AT
insn = THUMB_OP32 (opcode);
insn |= (old_op & 0xf0) << 4;
put_thumb32_insn (buf, insn);
- reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ if (opcode == T_MNEM_add_pc)
+ reloc_type = BFD_RELOC_ARM_T32_IMM12;
+ else
+ reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
}
else
reloc_type = BFD_RELOC_ARM_THUMB_ADD;
@@ -16153,7 +16168,10 @@ md_convert_frag (bfd *abfd, segT asec AT
insn |= (old_op & 0xf0) << 4;
insn |= (old_op & 0xf) << 16;
put_thumb32_insn (buf, insn);
- reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ if (insn & (1 << 20))
+ reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
+ else
+ reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
}
else
reloc_type = BFD_RELOC_ARM_THUMB_ADD;
@@ -17561,6 +17579,7 @@ md_apply_fix (fixS * fixP,
break;
case BFD_RELOC_ARM_T32_IMMEDIATE:
+ case BFD_RELOC_ARM_T32_ADD_IMM:
case BFD_RELOC_ARM_T32_IMM12:
case BFD_RELOC_ARM_T32_ADD_PC12:
/* We claim that this fixup has been processed here,
@@ -17581,15 +17600,21 @@ md_apply_fix (fixS * fixP,
newval <<= 16;
newval |= md_chars_to_number (buf+2, THUMB_SIZE);
- /* FUTURE: Implement analogue of negate_data_op for T32. */
- if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE)
+ newimm = FAIL;
+ if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
+ || fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
{
newimm = encode_thumb32_immediate (value);
if (newimm == (unsigned int) FAIL)
newimm = thumb32_negate_data_op (&newval, value);
}
- else
+ if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE
+ && newimm == (unsigned int) FAIL)
{
+ /* Turn add/sum into addw/subw. */
+ if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
+ newval = (newval & 0xfeffffff) | 0x02000000;
+
/* 12 bit immediate for addw/subw. */
if (value < 0)
{
@@ -18608,6 +18633,7 @@ arm_force_relocation (struct fix * fixp)
if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
|| fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
|| fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE
+ || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM
|| fixp->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
|| fixp->fx_r_type == BFD_RELOC_ARM_T32_IMM12
|| fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12)
Index: gas/testsuite/gas/arm/thumb2_add.d
===================================================================
RCS file: gas/testsuite/gas/arm/thumb2_add.d
diff -N gas/testsuite/gas/arm/thumb2_add.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/thumb2_add.d 12 Jul 2006 23:25:39 -0000
@@ -0,0 +1,18 @@
+# as: -march=armv6kt2
+# objdump: -dr --prefix-addresses --show-raw-insn
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0+000 <[^>]+> f60f 0000 addw r0, pc, #2048 ; 0x800
+0+004 <[^>]+> f20f 0900 addw r9, pc, #0 ; 0x0
+0+008 <[^>]+> f20f 4900 addw r9, pc, #1024 ; 0x400
+0+00c <[^>]+> f509 6880 add.w r8, r9, #1024 ; 0x400
+0+010 <[^>]+> f209 1801 addw r8, r9, #257 ; 0x101
+0+014 <[^>]+> f201 1301 addw r3, r1, #257 ; 0x101
+0+018 <[^>]+> f6af 0000 subw r0, pc, #2048 ; 0x800
+0+01c <[^>]+> f2af 0900 subw r9, pc, #0 ; 0x0
+0+020 <[^>]+> f2af 4900 subw r9, pc, #1024 ; 0x400
+0+024 <[^>]+> f5a9 6880 sub.w r8, r9, #1024 ; 0x400
+0+028 <[^>]+> f2a9 1801 subw r8, r9, #257 ; 0x101
+0+02c <[^>]+> f2a1 1301 subw r3, r1, #257 ; 0x101
Index: gas/testsuite/gas/arm/thumb2_add.s
===================================================================
RCS file: gas/testsuite/gas/arm/thumb2_add.s
diff -N gas/testsuite/gas/arm/thumb2_add.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/thumb2_add.s 12 Jul 2006 23:24:04 -0000
@@ -0,0 +1,20 @@
+ .syntax unified
+ .text
+ .align 2
+ .global thumb2_add
+ .thumb
+ .thumb_func
+ .type thumb2_add, %function
+thumb2_add:
+ add r0, pc, #0x800
+ add r9, pc, #0
+ add r9, pc, #0x400
+ add r8, r9, #0x400
+ add r8, r9, #0x101
+ add r3, r1, #0x101
+ sub r0, pc, #0x800
+ sub r9, pc, #0
+ sub r9, pc, #0x400
+ sub r8, r9, #0x400
+ sub r8, r9, #0x101
+ sub r3, r1, #0x101