[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