| Index: binutils/gas/config/tc-arm.c
|
| diff --git a/binutils/gas/config/tc-arm.c b/binutils/gas/config/tc-arm.c
|
| index 5f67171da32cf9bbb546b6b3014bd65350c9b0bf..69b0f92756cf7b9ffc0ef7dc13fc5d63968b4713 100644
|
| --- a/binutils/gas/config/tc-arm.c
|
| +++ b/binutils/gas/config/tc-arm.c
|
| @@ -2486,7 +2486,9 @@ make_mapping_symbol (enum mstate state, valueT value, fragS *frag)
|
| frag->tc_frag_data.first_map = symbolP;
|
| }
|
| if (frag->tc_frag_data.last_map != NULL)
|
| - know (S_GET_VALUE (frag->tc_frag_data.last_map) < S_GET_VALUE (symbolP));
|
| + {
|
| + know (S_GET_VALUE (frag->tc_frag_data.last_map) < S_GET_VALUE (symbolP));
|
| + }
|
| frag->tc_frag_data.last_map = symbolP;
|
| }
|
|
|
| @@ -19039,6 +19041,8 @@ md_pcrel_from_section (fixS * fixP, segT seg)
|
|
|
| case BFD_RELOC_THUMB_PCREL_BRANCH23:
|
| if (fixP->fx_addsy
|
| + && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
|
| + && (!S_IS_EXTERNAL (fixP->fx_addsy))
|
| && ARM_IS_FUNC (fixP->fx_addsy)
|
| && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
|
| base = fixP->fx_where + fixP->fx_frag->fr_address;
|
| @@ -19048,6 +19052,8 @@ md_pcrel_from_section (fixS * fixP, segT seg)
|
| zero. */
|
| case BFD_RELOC_THUMB_PCREL_BLX:
|
| if (fixP->fx_addsy
|
| + && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
|
| + && (!S_IS_EXTERNAL (fixP->fx_addsy))
|
| && THUMB_IS_FUNC (fixP->fx_addsy)
|
| && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
|
| base = fixP->fx_where + fixP->fx_frag->fr_address;
|
| @@ -19057,6 +19063,8 @@ md_pcrel_from_section (fixS * fixP, segT seg)
|
| loader expects the relocation not to take this into account. */
|
| case BFD_RELOC_ARM_PCREL_BLX:
|
| if (fixP->fx_addsy
|
| + && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
|
| + && (!S_IS_EXTERNAL (fixP->fx_addsy))
|
| && ARM_IS_FUNC (fixP->fx_addsy)
|
| && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
|
| base = fixP->fx_where + fixP->fx_frag->fr_address;
|
| @@ -19064,6 +19072,8 @@ md_pcrel_from_section (fixS * fixP, segT seg)
|
|
|
| case BFD_RELOC_ARM_PCREL_CALL:
|
| if (fixP->fx_addsy
|
| + && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
|
| + && (!S_IS_EXTERNAL (fixP->fx_addsy))
|
| && THUMB_IS_FUNC (fixP->fx_addsy)
|
| && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
|
| base = fixP->fx_where + fixP->fx_frag->fr_address;
|
| @@ -19381,6 +19391,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,
|
| @@ -20073,10 +20108,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
|
| @@ -20084,6 +20115,24 @@ md_apply_fix (fixS * fixP,
|
| 1 of the base address. */
|
| value = (value + 1) & ~ 1;
|
|
|
| + 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);
|
| +
|
| if (fixP->fx_done || !seg->use_rela_p)
|
| {
|
| offsetT newval2;
|
| @@ -20104,24 +20153,7 @@ md_apply_fix (fixS * fixP,
|
|
|
| if (fixP->fx_done || !seg->use_rela_p)
|
| {
|
| - offsetT newval2;
|
| - addressT S, I1, I2, lo, hi;
|
| -
|
| - 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);
|
| + encode_thumb2_b_bl_offset (buf, value);
|
| }
|
| break;
|
|
|
|
|