diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 9 | ||||
-rw-r--r-- | gas/config/tc-arm.c | 75 |
2 files changed, 52 insertions, 32 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 2de5f40..5301e06 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +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. + 2009-12-19 H.J. Lu <hongjiu.lu@intel.com> * config/tc-i386.c (process_operands): Check vexvvvv instead diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index c88e5f8..b7e8204 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -19536,6 +19536,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, @@ -20228,10 +20253,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 @@ -20239,17 +20260,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: @@ -20258,26 +20287,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: |