/* tc-arm.c -- Assemble for the ARM
- Copyright (C) 1994-2016 Free Software Foundation, Inc.
+ Copyright (C) 1994-2017 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)
/* Constants for known architecture features. */
static const arm_feature_set fpu_default = FPU_DEFAULT;
-static const arm_feature_set fpu_arch_vfp_v1 = FPU_ARCH_VFP_V1;
+static const arm_feature_set fpu_arch_vfp_v1 ATTRIBUTE_UNUSED = FPU_ARCH_VFP_V1;
static const arm_feature_set fpu_arch_vfp_v2 = FPU_ARCH_VFP_V2;
-static const arm_feature_set fpu_arch_vfp_v3 = FPU_ARCH_VFP_V3;
-static const arm_feature_set fpu_arch_neon_v1 = FPU_ARCH_NEON_V1;
+static const arm_feature_set fpu_arch_vfp_v3 ATTRIBUTE_UNUSED = FPU_ARCH_VFP_V3;
+static const arm_feature_set fpu_arch_neon_v1 ATTRIBUTE_UNUSED = FPU_ARCH_NEON_V1;
static const arm_feature_set fpu_arch_fpa = FPU_ARCH_FPA;
static const arm_feature_set fpu_any_hard = FPU_ANY_HARD;
+#ifdef OBJ_ELF
static const arm_feature_set fpu_arch_maverick = FPU_ARCH_MAVERICK;
+#endif
static const arm_feature_set fpu_endian_pure = FPU_ARCH_ENDIAN_PURE;
#ifdef CPU_DEFAULT
static const arm_feature_set arm_ext_v7 = ARM_FEATURE_CORE_LOW (ARM_EXT_V7);
static const arm_feature_set arm_ext_v7a = ARM_FEATURE_CORE_LOW (ARM_EXT_V7A);
static const arm_feature_set arm_ext_v7r = ARM_FEATURE_CORE_LOW (ARM_EXT_V7R);
+#ifdef OBJ_ELF
static const arm_feature_set arm_ext_v7m = ARM_FEATURE_CORE_LOW (ARM_EXT_V7M);
+#endif
static const arm_feature_set arm_ext_v8 = ARM_FEATURE_CORE_LOW (ARM_EXT_V8);
static const arm_feature_set arm_ext_m =
- ARM_FEATURE_CORE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M, ARM_EXT2_V8M);
+ ARM_FEATURE_CORE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M,
+ ARM_EXT2_V8M | ARM_EXT2_V8M_MAIN);
static const arm_feature_set arm_ext_mp = ARM_FEATURE_CORE_LOW (ARM_EXT_MP);
static const arm_feature_set arm_ext_sec = ARM_FEATURE_CORE_LOW (ARM_EXT_SEC);
static const arm_feature_set arm_ext_os = ARM_FEATURE_CORE_LOW (ARM_EXT_OS);
static const arm_feature_set arm_ext_virt = ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT);
static const arm_feature_set arm_ext_pan = ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN);
static const arm_feature_set arm_ext_v8m = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M);
+static const arm_feature_set arm_ext_v8m_main =
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN);
+/* Instructions in ARMv8-M only found in M profile architectures. */
+static const arm_feature_set arm_ext_v8m_m_only =
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M | ARM_EXT2_V8M_MAIN);
static const arm_feature_set arm_ext_v6t2_v8m =
ARM_FEATURE_CORE_HIGH (ARM_EXT2_V6T2_V8M);
/* Instructions shared between ARMv8-A and ARMv8-M. */
static const arm_feature_set arm_ext_atomics =
ARM_FEATURE_CORE_HIGH (ARM_EXT2_ATOMICS);
-static const arm_feature_set arm_ext_v8_2 =
- ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_2A);
+#ifdef OBJ_ELF
+/* DSP instructions Tag_DSP_extension refers to. */
+static const arm_feature_set arm_ext_dsp =
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V5E | ARM_EXT_V5ExP | ARM_EXT_V6_DSP);
+#endif
+static const arm_feature_set arm_ext_ras =
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_RAS);
/* FP16 instructions. */
static const arm_feature_set arm_ext_fp16 =
ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST);
+static const arm_feature_set arm_ext_v8_3 =
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A);
static const arm_feature_set arm_arch_any = ARM_ANY;
-static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1, -1);
+static const arm_feature_set arm_arch_full ATTRIBUTE_UNUSED = ARM_FEATURE (-1, -1, -1);
static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2;
static const arm_feature_set arm_arch_none = ARM_ARCH_NONE;
+#ifdef OBJ_ELF
static const arm_feature_set arm_arch_v6m_only = ARM_ARCH_V6M_ONLY;
+#endif
static const arm_feature_set arm_cext_iwmmxt2 =
ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2);
ARM_FEATURE_COPROC (FPU_NEON_EXT_V1);
static const arm_feature_set fpu_vfp_v3_or_neon_ext =
ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3);
+#ifdef OBJ_ELF
static const arm_feature_set fpu_vfp_fp16 =
ARM_FEATURE_COPROC (FPU_VFP_EXT_FP16);
static const arm_feature_set fpu_neon_ext_fma =
ARM_FEATURE_COPROC (FPU_NEON_EXT_FMA);
+#endif
static const arm_feature_set fpu_vfp_ext_fma =
ARM_FEATURE_COPROC (FPU_VFP_EXT_FMA);
static const arm_feature_set fpu_vfp_ext_armv8 =
#define T2_SUBS_PC_LR 0xf3de8f00
#define DATA_OP_SHIFT 21
+#define SBIT_SHIFT 20
#define T2_OPCODE_MASK 0xfe1fffff
#define T2_DATA_OP_SHIFT 21
+#define T2_SBIT_SHIFT 20
#define A_COND_MASK 0xf0000000
#define A_PUSH_POP_OP_MASK 0x0fff0000
if (*ccp != start && processor <= 15)
return processor;
}
+ /* Fall through. */
case REG_TYPE_MMXWC:
/* WC includes WCG. ??? I'm not sure this is true for all
const char *const incr_error = _("register stride must be 1 or 2");
const char *const type_error = _("mismatched element/structure types in list");
struct neon_typed_alias firsttype;
+ firsttype.defined = 0;
+ firsttype.eltype.type = NT_invtype;
+ firsttype.eltype.size = -1;
+ firsttype.index = -1;
if (skip_past_char (&ptr, '{') == SUCCESS)
leading_brace = 1;
}
name = xstrdup (str);
- new_reg = (struct reg_entry *) xmalloc (sizeof (struct reg_entry));
+ new_reg = XNEW (struct reg_entry);
new_reg->name = name;
new_reg->number = number;
if (atype)
{
- reg->neon = (struct neon_typed_alias *)
- xmalloc (sizeof (struct neon_typed_alias));
+ reg->neon = XNEW (struct neon_typed_alias);
*reg->neon = *atype;
}
}
nlen = strlen (newname);
#endif
- nbuf = xmalloc (nlen + 1);
- memcpy (nbuf, newname, nlen);
- nbuf[nlen] = '\0';
+ nbuf = xmemdup0 (newname, nlen);
/* Create aliases under the new name as stated; an all-lowercase
version of the new name; and an all-uppercase version of the new
namelen = strlen (newname);
#endif
- namebuf = xmalloc (namelen + 1);
- strncpy (namebuf, newname, namelen);
- namebuf[namelen] = '\0';
+ namebuf = xmemdup0 (newname, namelen);
insert_neon_reg_alias (namebuf, basereg->number, basetype,
typeinfo.defined != 0 ? &typeinfo : NULL);
Some Thumb instructions are alignment-sensitive modulo 4 bytes,
but themselves require 2-byte alignment; this applies to some
- PC- relative forms. However, these cases will invovle implicit
+ PC- relative forms. However, these cases will involve implicit
literal pool generation or an explicit .align >=2, both of
which will cause the section to me marked with sufficient
alignment. Thus, we don't handle those cases here. */
}
/* If name is not NULL, then it is used for marking the beginning of a
- function, wherease if it is NULL then it means the function end. */
+ function, whereas if it is NULL then it means the function end. */
static void
asmfunc_debug (const char * name)
{
if (pool == NULL)
{
/* Create a new pool. */
- pool = (literal_pool *) xmalloc (sizeof (* pool));
+ pool = XNEW (literal_pool);
if (! pool)
return NULL;
}
pool->literals[entry] = inst.reloc.exp;
+ pool->literals[entry].X_op = O_constant;
pool->literals[entry].X_add_number = 0;
pool->literals[entry++].X_md = (PADDING_SLOT << 8) | 4;
pool->next_free_entry += 1;
}
/* Can't use symbol_new here, so have to create a symbol and then at
- a later date assign it a value. Thats what these functions do. */
+ a later date assign it a value. That's what these functions do. */
static void
symbol_locate (symbolS * symbolP,
XXX Surely there is a cleaner way to do this. */
char *p = input_line_pointer;
int offset;
- char *save_buf = xmalloc (input_line_pointer - base);
+ char *save_buf = XNEWVEC (char, input_line_pointer - base);
memcpy (save_buf, base, input_line_pointer - base);
memmove (base + (input_line_pointer - before_reloc),
int error_code;
if (!is_immediate_prefix (**in))
- return FALSE;
-
- ++*in;
+ {
+ /* In unified syntax, all prefixes are optional. */
+ if (!unified_syntax)
+ return FALSE;
+ }
+ else
+ ++*in;
/* Accept #0x0 as a synonym for #0. */
if (strncmp (*in, "0x", 2) == 0)
OP_EXPi, /* same, with optional immediate prefix */
OP_EXPr, /* same, with optional relocation suffix */
OP_HALF, /* 0 .. 65535 or low/high reloc. */
+ OP_IROT1, /* VCADD rotate immediate: 90, 270. */
+ OP_IROT2, /* VCMLA rotate immediate: 0, 90, 180, 270. */
OP_CPSF, /* CPS flags */
OP_ENDI, /* Endianness specifier */
OP_APSR_RR, /* ARM register or "APSR_nzcv". */
OP_RRnpc_I0, /* ARM register or literal 0 */
- OP_RR_EXr, /* ARM register or expression with opt. reloc suff. */
+ OP_RR_EXr, /* ARM register or expression with opt. reloc stuff. */
OP_RR_EXi, /* ARM register or expression with imm prefix */
OP_RF_IF, /* FPA register or immediate */
OP_RIWR_RIWC, /* iWMMXt R or C reg */
The only binary encoding difference is the Coprocessor number. Coprocessor
9 is used for half-precision calculations or conversions. The format of the
- instruction is the same as the equivalent Coprocessor 10 instuction that
+ instruction is the same as the equivalent Coprocessor 10 instruction that
exists for Single-Precision operation. */
static void
static void
encode_arm_shift (int i)
{
+ /* register-shifted register. */
+ if (inst.operands[i].immisreg)
+ {
+ int op_index;
+ for (op_index = 0; op_index <= i; ++op_index)
+ {
+ /* Check the operand only when it's presented. In pre-UAL syntax,
+ if the destination register is the same as the first operand, two
+ register form of the instruction can be used. */
+ if (inst.operands[op_index].present && inst.operands[op_index].isreg
+ && inst.operands[op_index].reg == REG_PC)
+ as_warn (UNPRED_REG ("r15"));
+ }
+
+ if (inst.operands[i].imm == REG_PC)
+ as_warn (UNPRED_REG ("r15"));
+ }
+
if (inst.operands[i].shift_kind == SHIFT_RRX)
inst.instruction |= SHIFT_ROR << 5;
else
return TRUE;
}
}
- else if (t == CONST_VEC)
+ else if (t == CONST_VEC && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
{
int op = 0;
unsigned immbits = 0;
inst.instruction |= inst.operands[0].reg << 12;
}
+static void
+do_rn (void)
+{
+ inst.instruction |= inst.operands[0].reg << 16;
+}
+
static void
do_rd_rm (void)
{
constraint (Rn == REG_PC, BAD_PC);
}
+ /* Only check the MRRC{2} variants. */
+ if ((inst.instruction & 0x0FF00000) == 0x0C500000)
+ {
+ /* If Rd == Rn, error that the operation is
+ unpredictable (example MRRC p3,#1,r1,r1,c4). */
+ constraint (Rd == Rn, BAD_OVERLAP);
+ }
+
inst.instruction |= inst.operands[0].reg << 8;
inst.instruction |= inst.operands[1].imm << 4;
inst.instruction |= Rd << 12;
top = (inst.instruction & 0x00400000) != 0;
constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
- _(":lower16: not allowed this instruction"));
+ _(":lower16: not allowed in this instruction"));
constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
- _(":upper16: not allowed instruction"));
+ _(":upper16: not allowed in this instruction"));
inst.instruction |= inst.operands[0].reg << 12;
if (inst.reloc.type == BFD_RELOC_UNUSED)
{
}
/* Parse an add or subtract instruction. We get here with inst.instruction
- equalling any of THUMB_OPCODE_add, adds, sub, or subs. */
+ equaling any of THUMB_OPCODE_add, adds, sub, or subs. */
static void
do_t_add_sub (void)
top = (inst.instruction & 0x00800000) != 0;
if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
{
- constraint (top, _(":lower16: not allowed this instruction"));
+ constraint (top, _(":lower16: not allowed in this instruction"));
inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
}
else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
{
- constraint (!top, _(":upper16: not allowed this instruction"));
+ constraint (!top, _(":upper16: not allowed in this instruction"));
inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
}
if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6m))
{
if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_os)
- /* This only applies to the v6m howver, not later architectures. */
+ /* This only applies to the v6m however, not later architectures. */
&& ! ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7))
as_bad (_("SVC is not permitted on this architecture"));
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, arm_ext_os);
X(3, (D, Q, S), MIXED), \
X(4, (D, D, D, I), DOUBLE), \
X(4, (Q, Q, Q, I), QUAD), \
+ X(4, (D, D, S, I), DOUBLE), \
+ X(4, (Q, Q, S, I), QUAD), \
X(2, (F, F), SINGLE), \
X(3, (F, F, F), SINGLE), \
X(2, (F, I), SINGLE), \
do_vfp_nsyn_push (void)
{
nsyn_insert_sp ();
+
+ constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
+ _("register list must contain at least 1 and at most 16 "
+ "registers"));
+
if (inst.operands[1].issingle)
do_vfp_nsyn_opcode ("fstmdbs");
else
do_vfp_nsyn_pop (void)
{
nsyn_insert_sp ();
+
+ constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
+ _("register list must contain at least 1 and at most 16 "
+ "registers"));
+
if (inst.operands[1].issingle)
do_vfp_nsyn_opcode ("fldmias");
else
{
enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
- N_EQK, N_EQK, N_I16 | N_I32 | N_F32 | N_KEY);
+ N_EQK, N_EQK, N_I16 | N_I32 | N_F_16_32 | N_KEY);
NEON_ENCODE (SCALAR, inst);
neon_mul_mac (et, neon_quad (rs));
}
do_vrint_1 (neon_cvt_mode_m);
}
+static unsigned
+neon_scalar_for_vcmla (unsigned opnd, unsigned elsize)
+{
+ unsigned regno = NEON_SCALAR_REG (opnd);
+ unsigned elno = NEON_SCALAR_INDEX (opnd);
+
+ if (elsize == 16 && elno < 2 && regno < 16)
+ return regno | (elno << 4);
+ else if (elsize == 32 && elno == 0)
+ return regno;
+
+ first_error (_("scalar out of range"));
+ return 0;
+}
+
+static void
+do_vcmla (void)
+{
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_armv8),
+ _(BAD_FPU));
+ constraint (inst.reloc.exp.X_op != O_constant, _("expression too complex"));
+ unsigned rot = inst.reloc.exp.X_add_number;
+ constraint (rot != 0 && rot != 90 && rot != 180 && rot != 270,
+ _("immediate out of range"));
+ rot /= 90;
+ if (inst.operands[2].isscalar)
+ {
+ enum neon_shape rs = neon_select_shape (NS_DDSI, NS_QQSI, NS_NULL);
+ unsigned size = neon_check_type (3, rs, N_EQK, N_EQK,
+ N_KEY | N_F16 | N_F32).size;
+ unsigned m = neon_scalar_for_vcmla (inst.operands[2].reg, size);
+ inst.is_neon = 1;
+ inst.instruction = 0xfe000800;
+ inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+ inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+ inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+ inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+ inst.instruction |= LOW4 (m);
+ inst.instruction |= HI1 (m) << 5;
+ inst.instruction |= neon_quad (rs) << 6;
+ inst.instruction |= rot << 20;
+ inst.instruction |= (size == 32) << 23;
+ }
+ else
+ {
+ enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
+ unsigned size = neon_check_type (3, rs, N_EQK, N_EQK,
+ N_KEY | N_F16 | N_F32).size;
+ neon_three_same (neon_quad (rs), 0, -1);
+ inst.instruction &= 0x00ffffff; /* Undo neon_dp_fixup. */
+ inst.instruction |= 0xfc200800;
+ inst.instruction |= rot << 23;
+ inst.instruction |= (size == 32) << 20;
+ }
+}
+
+static void
+do_vcadd (void)
+{
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_armv8),
+ _(BAD_FPU));
+ constraint (inst.reloc.exp.X_op != O_constant, _("expression too complex"));
+ unsigned rot = inst.reloc.exp.X_add_number;
+ constraint (rot != 90 && rot != 270, _("immediate out of range"));
+ enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
+ unsigned size = neon_check_type (3, rs, N_EQK, N_EQK,
+ N_KEY | N_F16 | N_F32).size;
+ neon_three_same (neon_quad (rs), 0, -1);
+ inst.instruction &= 0x00ffffff; /* Undo neon_dp_fixup. */
+ inst.instruction |= 0xfc800800;
+ inst.instruction |= (rot == 270) << 24;
+ inst.instruction |= (size == 32) << 20;
+}
+
/* Crypto v1 instructions. */
static void
do_crypto_2op_1 (unsigned elttype, int op)
do_crc32_1 (1, 2);
}
+static void
+do_vjcvt (void)
+{
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+ _(BAD_FPU));
+ neon_check_type (2, NS_FD, N_S32, N_F64);
+ do_vfp_sp_dp_cvt ();
+ do_vfp_cond_or_thumb ();
+}
+
\f
/* Overall per-instruction processing. */
case OT_odd_infix_unc:
if (!unified_syntax)
return 0;
- /* else fall through */
+ /* Fall through. */
case OT_csuffix:
case OT_csuffixF:
set_it_insn_type_last () ditto
in_it_block () ditto
it_fsm_post_encode () from md_assemble ()
- force_automatic_it_block_close () from label habdling functions
+ force_automatic_it_block_close () from label handling functions
Rationale:
1) md_assemble () calls it_fsm_pre_encode () before calling tencode (),
for covering other cases.
Calling handle_it_state () may not transition the IT block state to
- OUTSIDE_IT_BLOCK immediatelly, since the (current) state could be
+ OUTSIDE_IT_BLOCK immediately, since the (current) state could be
still queried. Instead, if the FSM determines that the state should
be transitioned to OUTSIDE_IT_BLOCK, a flag is marked to be closed
after the tencode () function: that's what it_fsm_post_encode () does.
switch (inst.it_insn_type)
{
case OUTSIDE_IT_INSN:
- /* The closure of the block shall happen immediatelly,
+ /* The closure of the block shall happen immediately,
so any in_it_block () call reports the block as closed. */
force_automatic_it_block_close ();
break;
|| ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier))
return TRUE;
- /* Wide-only instruction added to ARMv8-M. */
- if (ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v8m)
+ /* Wide-only instruction added to ARMv8-M Baseline. */
+ if (ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v8m_m_only)
|| ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_atomics)
|| ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v6t2_v8m)
|| ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_div))
&& opcode->tencode == do_t_branch)
return TRUE;
+ /* MOV accepts T1/T3 encodings under Baseline, T3 encoding is 32bit. */
+ if (ARM_CPU_HAS_FEATURE (arch, arm_ext_v8m)
+ && opcode->tencode == do_t_mov_cmp
+ /* Make sure CMP instruction is not affected. */
+ && opcode->aencode == do_mov)
+ return TRUE;
+
/* Wide instruction variants of all instructions with narrow *and* wide
variants become available with ARMv6t2. Other opcodes are either
narrow-only or wide-only and are thus available if OPCODE is valid. */
/* Table of V7M psr names. */
static const struct asm_psr v7m_psrs[] =
{
- {"apsr", 0 }, {"APSR", 0 },
- {"iapsr", 1 }, {"IAPSR", 1 },
- {"eapsr", 2 }, {"EAPSR", 2 },
- {"psr", 3 }, {"PSR", 3 },
- {"xpsr", 3 }, {"XPSR", 3 }, {"xPSR", 3 },
- {"ipsr", 5 }, {"IPSR", 5 },
- {"epsr", 6 }, {"EPSR", 6 },
- {"iepsr", 7 }, {"IEPSR", 7 },
- {"msp", 8 }, {"MSP", 8 },
- {"psp", 9 }, {"PSP", 9 },
- {"primask", 16}, {"PRIMASK", 16},
- {"basepri", 17}, {"BASEPRI", 17},
- {"basepri_max", 18}, {"BASEPRI_MAX", 18},
- {"basepri_max", 18}, {"BASEPRI_MASK", 18}, /* Typo, preserved for backwards compatibility. */
- {"faultmask", 19}, {"FAULTMASK", 19},
- {"control", 20}, {"CONTROL", 20}
+ {"apsr", 0x0 }, {"APSR", 0x0 },
+ {"iapsr", 0x1 }, {"IAPSR", 0x1 },
+ {"eapsr", 0x2 }, {"EAPSR", 0x2 },
+ {"psr", 0x3 }, {"PSR", 0x3 },
+ {"xpsr", 0x3 }, {"XPSR", 0x3 }, {"xPSR", 3 },
+ {"ipsr", 0x5 }, {"IPSR", 0x5 },
+ {"epsr", 0x6 }, {"EPSR", 0x6 },
+ {"iepsr", 0x7 }, {"IEPSR", 0x7 },
+ {"msp", 0x8 }, {"MSP", 0x8 },
+ {"psp", 0x9 }, {"PSP", 0x9 },
+ {"msplim", 0xa }, {"MSPLIM", 0xa },
+ {"psplim", 0xb }, {"PSPLIM", 0xb },
+ {"primask", 0x10}, {"PRIMASK", 0x10},
+ {"basepri", 0x11}, {"BASEPRI", 0x11},
+ {"basepri_max", 0x12}, {"BASEPRI_MAX", 0x12},
+ {"faultmask", 0x13}, {"FAULTMASK", 0x13},
+ {"control", 0x14}, {"CONTROL", 0x14},
+ {"msp_ns", 0x88}, {"MSP_NS", 0x88},
+ {"psp_ns", 0x89}, {"PSP_NS", 0x89},
+ {"msplim_ns", 0x8a}, {"MSPLIM_NS", 0x8a},
+ {"psplim_ns", 0x8b}, {"PSPLIM_NS", 0x8b},
+ {"primask_ns", 0x90}, {"PRIMASK_NS", 0x90},
+ {"basepri_ns", 0x91}, {"BASEPRI_NS", 0x91},
+ {"faultmask_ns", 0x93}, {"FAULTMASK_NS", 0x93},
+ {"control_ns", 0x94}, {"CONTROL_NS", 0x94},
+ {"sp_ns", 0x98}, {"SP_NS", 0x98 }
};
/* Table of all shift-in-operand names. */
/* ARMv8.2 RAS extension. */
#undef ARM_VARIANT
-#define ARM_VARIANT & arm_ext_v8_2
+#define ARM_VARIANT & arm_ext_ras
#undef THUMB_VARIANT
-#define THUMB_VARIANT & arm_ext_v8_2
+#define THUMB_VARIANT & arm_ext_ras
TUE ("esb", 320f010, f3af8010, 0, (), noargs, noargs),
+#undef ARM_VARIANT
+#define ARM_VARIANT & arm_ext_v8_3
+#undef THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8_3
+ NCE (vjcvt, eb90bc0, 2, (RVS, RVD), vjcvt),
+ NUF (vcmla, 0, 4, (RNDQ, RNDQ, RNDQ_RNSC, EXPi), vcmla),
+ NUF (vcadd, 0, 4, (RNDQ, RNDQ, RNDQ, EXPi), vcadd),
+
#undef ARM_VARIANT
#define ARM_VARIANT & fpu_fpa_ext_v1 /* Core FPA instruction set (V1). */
#undef THUMB_VARIANT
cCE("cfmadda32", e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
cCE("cfmsuba32", e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
+ /* ARMv8-M instructions. */
#undef ARM_VARIANT
#define ARM_VARIANT NULL
#undef THUMB_VARIANT
#define THUMB_VARIANT & arm_ext_v8m
+ TUE("sg", 0, e97fe97f, 0, (), 0, noargs),
+ TUE("blxns", 0, 4784, 1, (RRnpc), 0, t_blx),
+ TUE("bxns", 0, 4704, 1, (RRnpc), 0, t_bx),
TUE("tt", 0, e840f000, 2, (RRnpc, RRnpc), 0, tt),
TUE("ttt", 0, e840f040, 2, (RRnpc, RRnpc), 0, tt),
+ TUE("tta", 0, e840f080, 2, (RRnpc, RRnpc), 0, tt),
+ TUE("ttat", 0, e840f0c0, 2, (RRnpc, RRnpc), 0, tt),
+
+ /* FP for ARMv8-M Mainline. Enabled for ARMv8-M Mainline because the
+ instructions behave as nop if no VFP is present. */
+#undef THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8m_main
+ TUEc("vlldm", 0, ec300a00, 1, (RRnpc), rn),
+ TUEc("vlstm", 0, ec200a00, 1, (RRnpc), rn),
};
#undef ARM_VARIANT
#undef THUMB_VARIANT
Note - despite the name this initialisation is not done when the frag
is created, but only when its type is assigned. A frag can be created
and used a long time before its type is set, so beware of assuming that
- this initialisationis performed first. */
+ this initialisation is performed first. */
#ifndef OBJ_ELF
void
{
unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
if (unwind.opcodes)
- unwind.opcodes = (unsigned char *) xrealloc (unwind.opcodes,
- unwind.opcode_alloc);
+ unwind.opcodes = XRESIZEVEC (unsigned char, unwind.opcodes,
+ unwind.opcode_alloc);
else
- unwind.opcodes = (unsigned char *) xmalloc (unwind.opcode_alloc);
+ unwind.opcodes = XNEWVEC (unsigned char, unwind.opcode_alloc);
}
while (length > 0)
{
const char * prefix;
const char * prefix_once;
const char * group_name;
- size_t prefix_len;
- size_t text_len;
char * sec_name;
- size_t sec_name_len;
int type;
int flags;
int linkonce;
text_name += strlen (".gnu.linkonce.t.");
}
- prefix_len = strlen (prefix);
- text_len = strlen (text_name);
- sec_name_len = prefix_len + text_len;
- sec_name = (char *) xmalloc (sec_name_len + 1);
- memcpy (sec_name, prefix, prefix_len);
- memcpy (sec_name + prefix_len, text_name, text_len);
- sec_name[prefix_len + text_len] = '\0';
+ sec_name = concat (prefix, text_name, (char *) NULL);
flags = SHF_ALLOC;
linkonce = 0;
changing the opcode. */
if (newimm == (unsigned int) FAIL)
newimm = negate_data_op (&temp, value);
+ /* MOV accepts both ARM modified immediate (A1 encoding) and
+ UINT16 (A2 encoding) when possible, MOVW only accepts UINT16.
+ When disassembling, MOV is preferred when there is no encoding
+ overlap. */
+ if (newimm == (unsigned int) FAIL
+ && ((temp >> DATA_OP_SHIFT) & 0xf) == OPCODE_MOV
+ && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2)
+ && !((temp >> SBIT_SHIFT) & 0x1)
+ && value >= 0 && value <= 0xffff)
+ {
+ /* Clear bits[23:20] to change encoding from A1 to A2. */
+ temp &= 0xff0fffff;
+ /* Encoding high 4bits imm. Code below will encode the remaining
+ low 12bits. */
+ temp |= (value & 0x0000f000) << 4;
+ newimm = value & 0x00000fff;
+ }
}
if (newimm == (unsigned int) FAIL)
case BFD_RELOC_ARM_OFFSET_IMM:
if (!fixP->fx_done && seg->use_rela_p)
value = 0;
+ /* Fall through. */
case BFD_RELOC_ARM_LITERAL:
sign = value > 0;
newval |= md_chars_to_number (buf+2, THUMB_SIZE);
newimm = FAIL;
- if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
+ if ((fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
+ /* ARMv8-M Baseline MOV will reach here, but it doesn't support
+ Thumb2 modified immediate encoding (T2). */
+ && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
|| fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
{
newimm = encode_thumb32_immediate (value);
if (newimm == (unsigned int) FAIL)
newimm = thumb32_negate_data_op (&newval, value);
}
- if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE
- && newimm == (unsigned int) FAIL)
+ if (newimm == (unsigned int) FAIL)
{
- /* Turn add/sum into addw/subw. */
- if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
- newval = (newval & 0xfeffffff) | 0x02000000;
- /* No flat 12-bit imm encoding for addsw/subsw. */
- if ((newval & 0x00100000) == 0)
+ if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE)
{
- /* 12 bit immediate for addw/subw. */
- if (value < 0)
+ /* Turn add/sum into addw/subw. */
+ if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
+ newval = (newval & 0xfeffffff) | 0x02000000;
+ /* No flat 12-bit imm encoding for addsw/subsw. */
+ if ((newval & 0x00100000) == 0)
{
- value = -value;
- newval ^= 0x00a00000;
+ /* 12 bit immediate for addw/subw. */
+ if (value < 0)
+ {
+ value = -value;
+ newval ^= 0x00a00000;
+ }
+ if (value > 0xfff)
+ newimm = (unsigned int) FAIL;
+ else
+ newimm = value;
+ }
+ }
+ else
+ {
+ /* MOV accepts both Thumb2 modified immediate (T2 encoding) and
+ UINT16 (T3 encoding), MOVW only accepts UINT16. When
+ disassembling, MOV is preferred when there is no encoding
+ overlap.
+ NOTE: MOV is using ORR opcode under Thumb 2 mode. */
+ if (((newval >> T2_DATA_OP_SHIFT) & 0xf) == T2_OPCODE_ORR
+ && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2_v8m)
+ && !((newval >> T2_SBIT_SHIFT) & 0x1)
+ && value >= 0 && value <=0xffff)
+ {
+ /* Toggle bit[25] to change encoding from T2 to T3. */
+ newval ^= 1 << 25;
+ /* Clear bits[19:16]. */
+ newval &= 0xfff0ffff;
+ /* Encoding high 4bits imm. Code below will encode the
+ remaining low 12bits. */
+ newval |= (value & 0x0000f000) << 4;
+ newimm = value & 0x00000fff;
}
- if (value > 0xfff)
- newimm = (unsigned int) FAIL;
- else
- newimm = value;
}
}
newval = md_chars_to_number (buf, INSN_SIZE);
fixP->fx_done = 0;
}
+ /* Fall through. */
case BFD_RELOC_ARM_PLT32:
#endif
arelent * reloc;
bfd_reloc_code_real_type code;
- reloc = (arelent *) xmalloc (sizeof (arelent));
+ reloc = XNEW (arelent);
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
code = BFD_RELOC_8_PCREL;
break;
}
+ /* Fall through. */
case BFD_RELOC_16:
if (fixp->fx_pcrel)
code = BFD_RELOC_16_PCREL;
break;
}
+ /* Fall through. */
case BFD_RELOC_32:
if (fixp->fx_pcrel)
code = BFD_RELOC_32_PCREL;
break;
}
+ /* Fall through. */
case BFD_RELOC_ARM_MOVW:
if (fixp->fx_pcrel)
code = BFD_RELOC_ARM_MOVW_PCREL;
break;
}
+ /* Fall through. */
case BFD_RELOC_ARM_MOVT:
if (fixp->fx_pcrel)
code = BFD_RELOC_ARM_MOVT_PCREL;
break;
}
+ /* Fall through. */
case BFD_RELOC_ARM_THUMB_MOVW:
if (fixp->fx_pcrel)
code = BFD_RELOC_ARM_THUMB_MOVW_PCREL;
break;
}
+ /* Fall through. */
case BFD_RELOC_ARM_THUMB_MOVT:
if (fixp->fx_pcrel)
code = BFD_RELOC_ARM_THUMB_MOVT_PCREL;
break;
}
+ /* Fall through. */
case BFD_RELOC_NONE:
case BFD_RELOC_ARM_PCREL_BRANCH:
/* If it's a .thumb_func, declare it as so,
otherwise tag label as .code 16. */
if (THUMB_IS_FUNC (sym))
- elf_sym->internal_elf_sym.st_target_internal
- = ST_BRANCH_TO_THUMB;
+ ARM_SET_SYM_BRANCH_TYPE (elf_sym->internal_elf_sym.st_target_internal,
+ ST_BRANCH_TO_THUMB);
else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
elf_sym->internal_elf_sym.st_info =
ELF_ST_INFO (bind, STT_ARM_16BIT);
"Cortex-A15"),
ARM_CPU_OPT ("cortex-a17", ARM_ARCH_V7VE, FPU_ARCH_NEON_VFP_V4,
"Cortex-A17"),
- ARM_CPU_OPT ("cortex-a32", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_CPU_OPT ("cortex-a32", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Cortex-A32"),
- ARM_CPU_OPT ("cortex-a35", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_CPU_OPT ("cortex-a35", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Cortex-A35"),
- ARM_CPU_OPT ("cortex-a53", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_CPU_OPT ("cortex-a53", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Cortex-A53"),
- ARM_CPU_OPT ("cortex-a57", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_CPU_OPT ("cortex-a57", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Cortex-A57"),
- ARM_CPU_OPT ("cortex-a72", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_CPU_OPT ("cortex-a72", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Cortex-A72"),
+ ARM_CPU_OPT ("cortex-a73", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ "Cortex-A73"),
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"),
ARM_CPU_OPT ("cortex-r8", ARM_ARCH_V7R_IDIV,
FPU_ARCH_VFP_V3D16,
"Cortex-R8"),
+ ARM_CPU_OPT ("cortex-m33", ARM_ARCH_V8M_MAIN_DSP,
+ FPU_NONE, "Cortex-M33"),
+ ARM_CPU_OPT ("cortex-m23", ARM_ARCH_V8M_BASE,
+ FPU_NONE, "Cortex-M23"),
ARM_CPU_OPT ("cortex-m7", ARM_ARCH_V7EM, FPU_NONE, "Cortex-M7"),
ARM_CPU_OPT ("cortex-m4", ARM_ARCH_V7EM, FPU_NONE, "Cortex-M4"),
ARM_CPU_OPT ("cortex-m3", ARM_ARCH_V7M, FPU_NONE, "Cortex-M3"),
ARM_CPU_OPT ("cortex-m1", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M1"),
ARM_CPU_OPT ("cortex-m0", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M0"),
ARM_CPU_OPT ("cortex-m0plus", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M0+"),
- ARM_CPU_OPT ("exynos-m1", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_CPU_OPT ("exynos-m1", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Samsung " \
"Exynos M1"),
- ARM_CPU_OPT ("qdf24xx", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_CPU_OPT ("falkor", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ "Qualcomm "
+ "Falkor"),
+ ARM_CPU_OPT ("qdf24xx", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Qualcomm "
"QDF24XX"),
/* 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,
+ ARM_CPU_OPT ("xgene2", ARM_ARCH_V8A_CRC, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"APM X-Gene 2"),
{ NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
ARM_ARCH_OPT ("armv8-a", ARM_ARCH_V8A, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv8.1-a", ARM_ARCH_V8_1A, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv8.2-a", ARM_ARCH_V8_2A, FPU_ARCH_VFP),
+ ARM_ARCH_OPT ("armv8.3-a", ARM_ARCH_V8_3A, FPU_ARCH_VFP),
ARM_ARCH_OPT ("xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP),
ARM_ARCH_OPT ("iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP),
ARM_ARCH_OPT ("iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP),
size_t name_len;
const arm_feature_set merge_value;
const arm_feature_set clear_value;
- const arm_feature_set allowed_archs;
+ /* List of architectures for which an extension is available. ARM_ARCH_NONE
+ indicates that an extension is available for all architectures while
+ ARM_ANY marks an empty entry. */
+ const arm_feature_set allowed_archs[2];
};
/* The following table must be in alphabetical order with a NULL last entry.
*/
-#define ARM_EXT_OPT(N, M, C, AA) { N, sizeof (N) - 1, M, C, AA }
+#define ARM_EXT_OPT(N, M, C, AA) { N, sizeof (N) - 1, M, C, { AA, ARM_ANY } }
+#define ARM_EXT_OPT2(N, M, C, AA1, AA2) { N, sizeof (N) - 1, M, C, {AA1, AA2} }
static const struct arm_option_extension_value_table arm_extensions[] =
{
ARM_EXT_OPT ("crc", ARCH_CRC_ARMV8, ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
ARM_EXT_OPT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8),
ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+ ARM_EXT_OPT ("dsp", ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+ ARM_FEATURE_CORE (ARM_EXT_V7M, ARM_EXT2_V8M)),
ARM_EXT_OPT ("fp", FPU_ARCH_VFP_ARMV8, ARM_FEATURE_COPROC (FPU_VFP_ARMV8),
ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
ARM_EXT_OPT ("fp16", ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
ARM_ARCH_V8_2A),
- ARM_EXT_OPT ("idiv", ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
+ ARM_EXT_OPT2 ("idiv", ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
- ARM_FEATURE_CORE_LOW (ARM_EXT_V7A | ARM_EXT_V7R)),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V7A),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V7R)),
ARM_EXT_OPT ("iwmmxt",ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT),
- ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT), ARM_ANY),
+ ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT), ARM_ARCH_NONE),
ARM_EXT_OPT ("iwmmxt2", ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2),
- ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2), ARM_ANY),
+ ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2), ARM_ARCH_NONE),
ARM_EXT_OPT ("maverick", ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK),
- ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK), ARM_ANY),
- ARM_EXT_OPT ("mp", ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
+ ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK), ARM_ARCH_NONE),
+ ARM_EXT_OPT2 ("mp", ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
- ARM_FEATURE_CORE_LOW (ARM_EXT_V7A | ARM_EXT_V7R)),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V7A),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V7R)),
ARM_EXT_OPT ("os", ARM_FEATURE_CORE_LOW (ARM_EXT_OS),
ARM_FEATURE_CORE_LOW (ARM_EXT_OS),
ARM_FEATURE_CORE_LOW (ARM_EXT_V6M)),
ARM_EXT_OPT ("pan", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN),
ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_PAN, 0),
ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+ ARM_EXT_OPT ("ras", ARM_FEATURE_CORE_HIGH (ARM_EXT2_RAS),
+ ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_RAS, 0),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
ARM_EXT_OPT ("rdma", FPU_ARCH_NEON_VFP_ARMV8_1,
ARM_FEATURE_COPROC (FPU_NEON_ARMV8 | FPU_NEON_EXT_RDMA),
ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
- ARM_EXT_OPT ("sec", ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
+ ARM_EXT_OPT2 ("sec", ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
- ARM_FEATURE_CORE_LOW (ARM_EXT_V6K | ARM_EXT_V7A)),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V6K),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V7A)),
ARM_EXT_OPT ("simd", FPU_ARCH_NEON_VFP_ARMV8,
ARM_FEATURE_COPROC (FPU_NEON_ARMV8),
ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT),
ARM_FEATURE_CORE_LOW (ARM_EXT_V7A)),
ARM_EXT_OPT ("xscale",ARM_FEATURE_COPROC (ARM_CEXT_XSCALE),
- ARM_FEATURE_COPROC (ARM_CEXT_XSCALE), ARM_ANY),
- { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, ARM_ARCH_NONE }
+ ARM_FEATURE_COPROC (ARM_CEXT_XSCALE), ARM_ARCH_NONE),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, { ARM_ARCH_NONE, ARM_ARCH_NONE } }
};
#undef ARM_EXT_OPT
{"softvfp+vfp", FPU_ARCH_VFP_V2},
{"vfp", FPU_ARCH_VFP_V2},
{"vfp9", FPU_ARCH_VFP_V2},
- {"vfp3", FPU_ARCH_VFP_V3}, /* For backwards compatbility. */
+ {"vfp3", FPU_ARCH_VFP_V3}, /* Undocumented, use vfpv3. */
{"vfp10", FPU_ARCH_VFP_V2},
{"vfp10-r0", FPU_ARCH_VFP_V1},
{"vfpxd", FPU_ARCH_VFP_V1xD},
{"vfpv3xd-fp16", FPU_ARCH_VFP_V3xD_FP16},
{"arm1020t", FPU_ARCH_VFP_V1},
{"arm1020e", FPU_ARCH_VFP_V2},
- {"arm1136jfs", FPU_ARCH_VFP_V2},
+ {"arm1136jfs", FPU_ARCH_VFP_V2}, /* Undocumented, use arm1136jf-s. */
{"arm1136jf-s", FPU_ARCH_VFP_V2},
{"maverick", FPU_ARCH_MAVERICK},
- {"neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1},
+ {"neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1},
+ {"neon-vfpv3", FPU_ARCH_VFP_V3_PLUS_NEON_V1},
{"neon-fp16", FPU_ARCH_NEON_FP16},
{"vfpv4", FPU_ARCH_VFP_V4},
{"vfpv4-d16", FPU_ARCH_VFP_V4D16},
static bfd_boolean
arm_parse_extension (const char *str, const arm_feature_set **opt_p)
{
- arm_feature_set *ext_set = (arm_feature_set *)
- xmalloc (sizeof (arm_feature_set));
+ arm_feature_set *ext_set = XNEW (arm_feature_set);
/* We insist on extensions being specified in alphabetical order, and with
extensions being added before being removed. We achieve this by having
or removing it (0) and only allowing it to change in the order
-1 -> 1 -> 0. */
const struct arm_option_extension_value_table * opt = NULL;
+ const arm_feature_set arm_any = ARM_ANY;
int adding_value = -1;
/* Copy the feature set, so that we can modify it. */
for (; opt->name != NULL; opt++)
if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
{
+ int i, nb_allowed_archs =
+ sizeof (opt->allowed_archs) / sizeof (opt->allowed_archs[0]);
/* Check we can apply the extension to this architecture. */
- if (!ARM_CPU_HAS_FEATURE (*ext_set, opt->allowed_archs))
+ for (i = 0; i < nb_allowed_archs; i++)
+ {
+ /* Empty entry. */
+ if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_any))
+ continue;
+ if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *ext_set))
+ break;
+ }
+ if (i == nb_allowed_archs)
{
as_bad (_("extension does not apply to the base architecture"));
return FALSE;
char profile;
int virt_sec = 0;
int fp16_optional = 0;
+ arm_feature_set arm_arch = ARM_ARCH_NONE;
arm_feature_set flags;
arm_feature_set tmp;
arm_feature_set arm_arch_v8m_base = ARM_ARCH_V8M_BASE;
if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
{
arch = p->val;
+ arm_arch = p->flags;
ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
}
}
&& !ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
&& ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m)
&& ARM_CPU_HAS_FEATURE (flags, arm_ext_v6_dsp))
- arch = TAG_CPU_ARCH_V7E_M;
+ {
+ arch = TAG_CPU_ARCH_V7E_M;
+ arm_arch = (arm_feature_set) ARM_ARCH_V7EM;
+ }
ARM_CLEAR_FEATURE (tmp, flags, arm_arch_v8m_base);
if (arch == TAG_CPU_ARCH_V8M_BASE && ARM_CPU_HAS_FEATURE (tmp, arm_arch_any))
- arch = TAG_CPU_ARCH_V8M_MAIN;
+ {
+ arch = TAG_CPU_ARCH_V8M_MAIN;
+ arm_arch = (arm_feature_set) ARM_ARCH_V8M_MAIN;
+ }
/* In cpu_arch_ver ARMv8-A is before ARMv8-M for atomics to be detected as
coming from ARMv8-A. However, since ARMv8-A has more instructions than
ARMv8-M, -march=all must be detected as ARMv8-A. */
if (arch == TAG_CPU_ARCH_V8M_MAIN
&& ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any))
- arch = TAG_CPU_ARCH_V8;
+ {
+ arch = TAG_CPU_ARCH_V8;
+ arm_arch = (arm_feature_set) ARM_ARCH_V8A;
+ }
/* Tag_CPU_name. */
if (selected_cpu_name[0])
if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
|| ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
|| (ARM_CPU_HAS_FEATURE (flags, arm_ext_atomics)
- && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m)))
+ && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m_m_only)))
profile = 'A';
else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
profile = 'R';
if (profile != '\0')
aeabi_set_attribute_int (Tag_CPU_arch_profile, profile);
+ /* Tag_DSP_extension. */
+ if (ARM_CPU_HAS_FEATURE (flags, arm_ext_dsp))
+ {
+ arm_feature_set ext;
+
+ /* DSP instructions not in architecture. */
+ ARM_CLEAR_FEATURE (ext, flags, arm_arch);
+ if (ARM_CPU_HAS_FEATURE (ext, arm_ext_dsp))
+ aeabi_set_attribute_int (Tag_DSP_extension, 1);
+ }
+
/* Tag_ARM_ISA_use. */
if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v1)
|| arch == 0)
int thumb_isa_use;
if (!ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
- && ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m))
+ && ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m_m_only))
thumb_isa_use = 3;
else if (ARM_CPU_HAS_FEATURE (flags, arm_arch_t2))
thumb_isa_use = 2;
s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
{
const struct arm_option_extension_value_table *opt;
+ const arm_feature_set arm_any = ARM_ANY;
char saved_char;
char *name;
int adding_value = 1;
for (opt = arm_extensions; opt->name != NULL; opt++)
if (streq (opt->name, name))
{
- if (!ARM_CPU_HAS_FEATURE (*mcpu_cpu_opt, opt->allowed_archs))
+ int i, nb_allowed_archs =
+ sizeof (opt->allowed_archs) / sizeof (opt->allowed_archs[i]);
+ for (i = 0; i < nb_allowed_archs; i++)
+ {
+ /* Empty entry. */
+ if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_any))
+ continue;
+ if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *mcpu_cpu_opt))
+ break;
+ }
+
+ if (i == nb_allowed_archs)
{
as_bad (_("architectural extension `%s' is not allowed for the "
"current base architecture"), name);
T (Tag_conformance),
T (Tag_T2EE_use),
T (Tag_Virtualization_use),
+ T (Tag_DSP_extension),
/* We deliberately do not include Tag_MPextension_use_legacy. */
#undef T
};