[Patch ARM] Fix b / bl ranges for Thumb2.

Ramana Radhakrishnan ramana.radhakrishnan@arm.com
Mon Dec 21 12:02:00 GMT 2009


Hi,

In stage1 of a bootstrap of GCC in Thumb2 state, I came across a problem
with unconditional calls going out of range in Thumb2. This was because
the assembler ends up with encoding a bl within the function with the
Thumb1 bl instruction rather than the Thumb2 instruction. With some help
from Richard, I've now fixed this with the attached patch. 

This refactors some of the code from md_apply_fix into a separate
function of its own and rewrites some of the masking code in a form more
friendly to immediate generation on the ARM.

Tested cross on arm-eabi with no regressions. Ok to commit on trunk and
backport to the 2.20 branch ? 

cheers
Ramana

2009-12-21  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
	    Richard Earnshaw  <richard.earnshaw@arm.com>

	* config/tc-arm.c (encode_thumb2_b_bl_offset): New. Refactored
	from md_apply_fix.
	(md_apply_fix): Fixup range checks for Thumb2 version 
	of unconditional calls. Call encode_thumb2_b_bl_offset for 
	unconditional branches / function calls.



-------------- next part --------------
commit a87e23ee88b01c224e8df3628e290f134d4fe3fd
Author: Ramana Radhakrishnan <ramrad01@e200593-lin.cambridge.arm.com>
Date:   Mon Dec 21 11:05:57 2009 +0000

    Commit Fix for bl and b encoding for Thumb2

diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 65d81a9..01e9f3a 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -19532,6 +19532,31 @@ arm_optimize_expr (expressionS *l, operatorT op, expressionS *r)
   return FALSE;
 }
 
+/* Encode Thumb2 unconditional branches and calls. The encoding
+   for the 2 are identical for the immediate values.  */
+
+static void
+encode_thumb2_b_bl_offset (char * buf, offsetT value)
+{
+#define T2I1I2MASK  ((1 << 13) | (1 << 11))
+  offsetT newval;
+  offsetT newval2;
+  addressT S, I1, I2, lo, hi;
+
+  S = (value >> 24) & 0x01;
+  I1 = (value >> 23) & 0x01;
+  I2 = (value >> 22) & 0x01;
+  hi = (value >> 12) & 0x3ff;
+  lo = (value >> 1) & 0x7ff; 
+  newval   = md_chars_to_number (buf, THUMB_SIZE);
+  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+  newval  |= (S << 10) | hi;
+  newval2 &=  ~T2I1I2MASK;
+  newval2 |= (((I1 ^ S) << 13) | ((I2 ^ S) << 11) | lo) ^ T2I1I2MASK;
+  md_number_to_chars (buf, newval, THUMB_SIZE);
+  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+}
+
 void
 md_apply_fix (fixS *	fixP,
 	       valueT * valP,
@@ -20224,10 +20249,6 @@ md_apply_fix (fixS *	fixP,
 	 fixP->fx_r_type = BFD_RELOC_THUMB_PCREL_BRANCH23;
 #endif
 
-      if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
-	as_bad_where (fixP->fx_file, fixP->fx_line,
-		      _("branch out of range"));
-
       if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
 	/* For a BLX instruction, make sure that the relocation is rounded up
 	   to a word boundary.  This follows the semantics of the instruction
@@ -20235,17 +20256,25 @@ md_apply_fix (fixS *	fixP,
 	   1 of the base address.  */
 	value = (value + 1) & ~ 1;
 
-      if (fixP->fx_done || !seg->use_rela_p)
-	{
-	  offsetT newval2;
 
-	  newval   = md_chars_to_number (buf, THUMB_SIZE);
-	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
-	  newval  |= (value & 0x7fffff) >> 12;
-	  newval2 |= (value & 0xfff) >> 1;
-	  md_number_to_chars (buf, newval, THUMB_SIZE);
-	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+       if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
+	{
+	  if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2)))
+	    {
+	      as_bad_where (fixP->fx_file, fixP->fx_line,
+			    _("branch out of range"));
+	    }
+	  else
+	    if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
+	      {
+		as_bad_where (fixP->fx_file, fixP->fx_line,
+			    _("Thumb2 branch out of range"));
+	      }
 	}
+
+      if (fixP->fx_done || !seg->use_rela_p)
+	encode_thumb2_b_bl_offset (buf, value);
+
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH25:
@@ -20254,26 +20283,8 @@ md_apply_fix (fixS *	fixP,
 		      _("branch out of range"));
 
       if (fixP->fx_done || !seg->use_rela_p)
-	{
-	  offsetT newval2;
-	  addressT S, I1, I2, lo, hi;
+	  encode_thumb2_b_bl_offset (buf, value);
 
-	  S  = (value & 0x01000000) >> 24;
-	  I1 = (value & 0x00800000) >> 23;
-	  I2 = (value & 0x00400000) >> 22;
-	  hi = (value & 0x003ff000) >> 12;
-	  lo = (value & 0x00000ffe) >> 1;
-
-	  I1 = !(I1 ^ S);
-	  I2 = !(I2 ^ S);
-
-	  newval   = md_chars_to_number (buf, THUMB_SIZE);
-	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
-	  newval  |= (S << 10) | hi;
-	  newval2 |= (I1 << 13) | (I2 << 11) | lo;
-	  md_number_to_chars (buf, newval, THUMB_SIZE);
-	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
-	}
       break;
 
     case BFD_RELOC_8:


More information about the Binutils mailing list