/* tc-arm.c -- Assemble for the ARM
- Copyright (C) 1994-2014 Free Software Foundation, Inc.
+ Copyright (C) 1994-2015 Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
Modified by David Taylor (dtaylor@armltd.co.uk)
Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
/* Set the mapping state to STATE. Only call this when about to
emit some STATE bytes to the file. */
+#define TRANSITION(from, to) (mapstate == (from) && state == (to))
void
mapping_state (enum mstate state)
{
enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
-#define TRANSITION(from, to) (mapstate == (from) && state == (to))
-
if (mapstate == state)
/* The mapping symbol has already been emitted.
There is nothing else to do. */
record_alignment (now_seg, state == MAP_ARM ? 2 : 1);
if (TRANSITION (MAP_UNDEFINED, MAP_DATA))
- /* This case will be evaluated later in the next else. */
+ /* This case will be evaluated later. */
return;
- else if (TRANSITION (MAP_UNDEFINED, MAP_ARM)
- || TRANSITION (MAP_UNDEFINED, MAP_THUMB))
- {
- /* Only add the symbol if the offset is > 0:
- if we're at the first frag, check it's size > 0;
- if we're not at the first frag, then for sure
- the offset is > 0. */
- struct frag * const frag_first = seg_info (now_seg)->frchainP->frch_root;
- const int add_symbol = (frag_now != frag_first) || (frag_now_fix () > 0);
-
- if (add_symbol)
- make_mapping_symbol (MAP_DATA, (valueT) 0, frag_first);
- }
mapping_state_2 (state, 0);
-#undef TRANSITION
}
/* Same as mapping_state, but MAX_CHARS bytes have already been
There is nothing else to do. */
return;
+ if (TRANSITION (MAP_UNDEFINED, MAP_ARM)
+ || TRANSITION (MAP_UNDEFINED, MAP_THUMB))
+ {
+ struct frag * const frag_first = seg_info (now_seg)->frchainP->frch_root;
+ const int add_symbol = (frag_now != frag_first) || (frag_now_fix () > 0);
+
+ if (add_symbol)
+ make_mapping_symbol (MAP_DATA, (valueT) 0, frag_first);
+ }
+
seg_info (now_seg)->tc_segment_info_data.mapstate = state;
make_mapping_symbol (state, (valueT) frag_now_fix () - max_chars, frag_now);
}
+#undef TRANSITION
#else
#define mapping_state(x) ((void)0)
#define mapping_state_2(x, y) ((void)0)
return FALSE;
++*in;
+
+ /* Accept #0x0 as a synonym for #0. */
+ if (strncmp (*in, "0x", 2) == 0)
+ {
+ int val;
+ if (parse_immediate (in, &val, 0, 0, TRUE) == FAIL)
+ return FALSE;
+ return TRUE;
+ }
+
error_code = atof_generic (in, ".", EXP_CHARS,
&generic_floating_point_number);
val = parse_reg_list (&str);
if (*str == '^')
{
- inst.operands[1].writeback = 1;
+ inst.operands[i].writeback = 1;
str++;
}
break;
#define warn_deprecated_sp(reg) \
do \
if (warn_on_deprecated && reg == REG_SP) \
- as_warn (_("use of r13 is deprecated")); \
+ as_tsktsk (_("use of r13 is deprecated")); \
while (0)
/* Functions for operand encoding. ARM, then Thumb. */
if (warn_on_deprecated
&& !is_load
&& ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7))
- as_warn (_("use of PC in this instruction is deprecated"));
+ as_tsktsk (_("use of PC in this instruction is deprecated"));
}
if (inst.reloc.type == BFD_RELOC_UNUSED)
{
if (ARM_CPU_IS_ANY (cpu_variant))
{
- as_warn ("%s", msg);
+ as_tsktsk ("%s", msg);
return TRUE;
}
else if (ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
_("swp{b} use is obsoleted for ARMv8 and later"))
&& warn_on_deprecated
&& ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6))
- as_warn (_("swp{b} use is deprecated for ARMv6 and ARMv7"));
+ as_tsktsk (_("swp{b} use is deprecated for ARMv6 and ARMv7"));
}
inst.instruction |= inst.operands[0].reg << 12;
if (! ARM_CPU_IS_ANY (cpu_variant)
&& warn_on_deprecated
&& ARM_CPU_HAS_FEATURE (cpu_variant, r->deprecated))
- as_warn ("%s", r->dep_msg);
+ as_tsktsk ("%s", r->dep_msg);
}
}
static void
do_push_pop (void)
{
+ constraint (inst.operands[0].writeback,
+ _("push/pop do not support {reglist}^"));
inst.operands[1] = inst.operands[0];
memset (&inst.operands[0], 0, sizeof inst.operands[0]);
inst.operands[0].isreg = 1;
{
if (warn_on_deprecated
&& ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
- as_warn (_("setend use is deprecated for ARMv8"));
+ as_tsktsk (_("setend use is deprecated for ARMv8"));
if (inst.operands[0].imm)
inst.instruction |= 0x200;
if ((Rn == REG_SP || Rn == REG_PC)
&& (Rm == REG_SP || Rm == REG_PC))
{
- as_warn (_("Use of r%u as a source register is "
+ as_tsktsk (_("Use of r%u as a source register is "
"deprecated when r%u is the destination "
"register."), Rm, Rn);
}
{
if (warn_on_deprecated
&& ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
- as_warn (_("setend use is deprecated for ARMv8"));
+ as_tsktsk (_("setend use is deprecated for ARMv8"));
set_it_insn_type (OUTSIDE_IT_INSN);
if (inst.operands[0].imm)
{
enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
+ int imm = inst.operands[2].imm;
+
+ constraint (imm < 0 || (unsigned)imm >= et.size,
+ _("immediate out of range for shift"));
NEON_ENCODE (IMMED, inst);
- neon_imm_shift (FALSE, 0, neon_quad (rs), et, inst.operands[2].imm);
+ neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
}
else
{
{
enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
+ int imm = inst.operands[2].imm;
+ constraint (imm < 0 || (unsigned)imm >= et.size,
+ _("immediate out of range for shift"));
NEON_ENCODE (IMMED, inst);
- neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
- inst.operands[2].imm);
+ neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et, imm);
}
else
{
if (thumb_mode)
inst.error = _("Use of PC here is UNPREDICTABLE");
else if (warn_on_deprecated)
- as_warn (_("Use of PC here is deprecated"));
+ as_tsktsk (_("Use of PC here is deprecated"));
}
if (inst.operands[0].issingle)
}
if (warn_on_deprecated && unified_syntax)
- as_warn (_("conditional infixes are deprecated in unified syntax"));
+ as_tsktsk (_("conditional infixes are deprecated in unified syntax"));
affix = base + (opcode->tag - OT_odd_infix_0);
cond = (const struct asm_cond *) hash_find_n (arm_cond_hsh, affix, 2);
gas_assert (cond);
if (warn_on_deprecated && unified_syntax
&& (opcode->tag == OT_cinfix3
|| opcode->tag == OT_cinfix3_deprecated))
- as_warn (_("conditional infixes are deprecated in unified syntax"));
+ as_tsktsk (_("conditional infixes are deprecated in unified syntax"));
inst.cond = cond->value;
return opcode;
{
if (inst.instruction >= 0x10000)
{
- as_warn (_("IT blocks containing 32-bit Thumb instructions are "
+ as_tsktsk (_("IT blocks containing 32-bit Thumb instructions are "
"deprecated in ARMv8"));
now_it.warn_deprecated = TRUE;
}
{
if ((inst.instruction & p->mask) == p->pattern)
{
- as_warn (_("IT blocks containing 16-bit Thumb instructions "
+ as_tsktsk (_("IT blocks containing 16-bit Thumb instructions "
"of the following class are deprecated in ARMv8: "
"%s"), p->description);
now_it.warn_deprecated = TRUE;
if (now_it.block_length > 1)
{
- as_warn (_("IT blocks containing more than one conditional "
+ as_tsktsk (_("IT blocks containing more than one conditional "
"instruction are deprecated in ARMv8"));
now_it.warn_deprecated = TRUE;
}
}
if (warn_on_deprecated && opcode->tag == OT_cinfix3_deprecated)
- as_warn (_("s suffix on comparison instruction is deprecated"));
+ as_tsktsk (_("s suffix on comparison instruction is deprecated"));
/* The value which unconditional instructions should have in place of the
condition field. */
/* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
set those bits when Thumb-2 32-bit instructions are seen. ie.
anything other than bl/blx and v6-M instructions.
- This is overly pessimistic for relaxable instructions. */
- if (((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
- || inst.relax)
+ The impact of relaxable instructions will be considered later after we
+ finish all relaxation. */
+ if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
&& !(ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
|| ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier)))
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
fragp->fr_fix += fragp->fr_var;
+
+ /* Set whether we use thumb-2 ISA based on final relaxation results. */
+ if (thumb_mode && fragp->fr_var == 4 && no_cpu_selected ()
+ && !ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2))
+ ARM_MERGE_FEATURE_SETS (arm_arch_used, thumb_arch_used, arm_ext_v6t2);
}
/* Return the size of a relaxable immediate operand instruction.
mcpu_cpu_opt = &cpu_default;
selected_cpu = cpu_default;
}
+ else if (no_cpu_selected ())
+ selected_cpu = cpu_default;
#else
if (mcpu_cpu_opt)
selected_cpu = *mcpu_cpu_opt;
"Cortex-A53"),
ARM_CPU_OPT ("cortex-a57", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Cortex-A57"),
+ ARM_CPU_OPT ("cortex-a72", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ "Cortex-A72"),
ARM_CPU_OPT ("cortex-r4", ARM_ARCH_V7R, FPU_NONE, "Cortex-R4"),
ARM_CPU_OPT ("cortex-r4f", ARM_ARCH_V7R, FPU_ARCH_VFP_V3D16,
"Cortex-R4F"),
/* Marvell processors. */
ARM_CPU_OPT ("marvell-pj4", ARM_FEATURE (ARM_AEXT_V7A | ARM_EXT_MP | ARM_EXT_SEC, 0),
FPU_ARCH_VFP_V3D16, NULL),
+ ARM_CPU_OPT ("marvell-whitney", ARM_FEATURE (ARM_AEXT_V7A | ARM_EXT_MP
+ | ARM_EXT_SEC, 0),
+ FPU_ARCH_NEON_VFP_V4, NULL),
+ /* APM X-Gene family. */
+ ARM_CPU_OPT ("xgene1", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ "APM X-Gene 1"),
+ ARM_CPU_OPT ("xgene2", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ "APM X-Gene 2"),
{ NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
};
{
char *name;
size_t name_len;
- const arm_feature_set value;
+ const arm_feature_set merge_value;
+ const arm_feature_set clear_value;
const arm_feature_set allowed_archs;
};
/* The following table must be in alphabetical order with a NULL last entry.
*/
-#define ARM_EXT_OPT(N, V, AA) { N, sizeof (N) - 1, V, AA }
+#define ARM_EXT_OPT(N, M, C, AA) { N, sizeof (N) - 1, M, C, AA }
static const struct arm_option_extension_value_table arm_extensions[] =
{
- ARM_EXT_OPT ("crc", ARCH_CRC_ARMV8, ARM_FEATURE (ARM_EXT_V8, 0)),
+ ARM_EXT_OPT ("crc", ARCH_CRC_ARMV8, ARM_FEATURE (0, CRC_EXT_ARMV8),
+ ARM_FEATURE (ARM_EXT_V8, 0)),
ARM_EXT_OPT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_FEATURE (0, FPU_CRYPTO_ARMV8),
ARM_FEATURE (ARM_EXT_V8, 0)),
- ARM_EXT_OPT ("fp", FPU_ARCH_VFP_ARMV8,
+ ARM_EXT_OPT ("fp", FPU_ARCH_VFP_ARMV8, ARM_FEATURE (0, FPU_VFP_ARMV8),
ARM_FEATURE (ARM_EXT_V8, 0)),
ARM_EXT_OPT ("idiv", ARM_FEATURE (ARM_EXT_ADIV | ARM_EXT_DIV, 0),
+ ARM_FEATURE (ARM_EXT_ADIV | ARM_EXT_DIV, 0),
ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)),
- ARM_EXT_OPT ("iwmmxt",ARM_FEATURE (0, ARM_CEXT_IWMMXT), ARM_ANY),
- ARM_EXT_OPT ("iwmmxt2",
- ARM_FEATURE (0, ARM_CEXT_IWMMXT2), ARM_ANY),
- ARM_EXT_OPT ("maverick",
- ARM_FEATURE (0, ARM_CEXT_MAVERICK), ARM_ANY),
+ ARM_EXT_OPT ("iwmmxt",ARM_FEATURE (0, ARM_CEXT_IWMMXT),
+ ARM_FEATURE (0, ARM_CEXT_IWMMXT), ARM_ANY),
+ ARM_EXT_OPT ("iwmmxt2", ARM_FEATURE (0, ARM_CEXT_IWMMXT2),
+ ARM_FEATURE (0, ARM_CEXT_IWMMXT2), ARM_ANY),
+ ARM_EXT_OPT ("maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK),
+ ARM_FEATURE (0, ARM_CEXT_MAVERICK), ARM_ANY),
ARM_EXT_OPT ("mp", ARM_FEATURE (ARM_EXT_MP, 0),
+ ARM_FEATURE (ARM_EXT_MP, 0),
ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)),
ARM_EXT_OPT ("simd", FPU_ARCH_NEON_VFP_ARMV8,
+ ARM_FEATURE(0, FPU_NEON_ARMV8),
ARM_FEATURE (ARM_EXT_V8, 0)),
ARM_EXT_OPT ("os", ARM_FEATURE (ARM_EXT_OS, 0),
+ ARM_FEATURE (ARM_EXT_OS, 0),
ARM_FEATURE (ARM_EXT_V6M, 0)),
ARM_EXT_OPT ("sec", ARM_FEATURE (ARM_EXT_SEC, 0),
+ ARM_FEATURE (ARM_EXT_SEC, 0),
ARM_FEATURE (ARM_EXT_V6K | ARM_EXT_V7A, 0)),
ARM_EXT_OPT ("virt", ARM_FEATURE (ARM_EXT_VIRT | ARM_EXT_ADIV
| ARM_EXT_DIV, 0),
+ ARM_FEATURE (ARM_EXT_VIRT, 0),
ARM_FEATURE (ARM_EXT_V7A, 0)),
- ARM_EXT_OPT ("xscale",ARM_FEATURE (0, ARM_CEXT_XSCALE), ARM_ANY),
- { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+ ARM_EXT_OPT ("xscale",ARM_FEATURE (0, ARM_CEXT_XSCALE),
+ ARM_FEATURE (0, ARM_CEXT_XSCALE), ARM_ANY),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, ARM_ARCH_NONE }
};
#undef ARM_EXT_OPT
/* Add or remove the extension. */
if (adding_value)
- ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
+ ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->merge_value);
else
- ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->value);
+ ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->clear_value);
break;
}
}
/* Set the public EABI object attributes. */
-static void
+void
aeabi_set_public_attributes (void)
{
int arch;
}
if (adding_value)
- ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu, opt->value);
+ ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu,
+ opt->merge_value);
else
- ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->value);
+ ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->clear_value);
mcpu_cpu_opt = &selected_cpu;
ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
}
-/* Apply sym value for relocations only in the case that
- they are for local symbols and you have the respective
- architectural feature for blx and simple switches. */
+/* Apply sym value for relocations only in the case that they are for
+ local symbols in the same segment as the fixup and you have the
+ respective architectural feature for blx and simple switches. */
int
-arm_apply_sym_value (struct fix * fixP)
+arm_apply_sym_value (struct fix * fixP, segT this_seg)
{
if (fixP->fx_addsy
&& ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t)
+ /* PR 17444: If the local symbol is in a different section then a reloc
+ will always be generated for it, so applying the symbol value now
+ will result in a double offset being stored in the relocation. */
+ && (S_GET_SEGMENT (fixP->fx_addsy) == this_seg)
&& !S_FORCE_RELOC (fixP->fx_addsy, TRUE))
{
switch (fixP->fx_r_type)
case BFD_RELOC_ARM_PCREL_CALL:
case BFD_RELOC_THUMB_PCREL_BLX:
if (THUMB_IS_FUNC (fixP->fx_addsy))
- return 1;
+ return 1;
break;
default: