This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]