input_line_pointer = save_in;
return 1;
}
+#else
+ (void) seg;
#endif
/* Get rid of any bignums now, so that we don't generate an error for which
int lane = -1;
int leading_brace = 0;
enum arm_reg_type rtype = REG_TYPE_NDQ;
- int addregs = 1;
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;
if (rtype == REG_TYPE_NQ)
{
reg_incr = 1;
- addregs = 2;
}
firsttype = atype;
}
/* Never reached. */
}
+/* Parse a Neon alignment expression. Information is written to
+ inst.operands[i]. We assume the initial ':' has been skipped.
+
+ align .imm = align << 8, .immisalign=1, .preind=0 */
+static parse_operand_result
+parse_neon_alignment (char **str, int i)
+{
+ char *p = *str;
+ expressionS exp;
+
+ my_get_expression (&exp, &p, GE_NO_PREFIX);
+
+ if (exp.X_op != O_constant)
+ {
+ inst.error = _("alignment must be constant");
+ return PARSE_OPERAND_FAIL;
+ }
+
+ inst.operands[i].imm = exp.X_add_number << 8;
+ inst.operands[i].immisalign = 1;
+ /* Alignments are not pre-indexes. */
+ inst.operands[i].preind = 0;
+
+ *str = p;
+ return PARSE_OPERAND_SUCCESS;
+}
+
/* Parse all forms of an ARM address expression. Information is written
to inst.operands[i] and/or inst.reloc.
return PARSE_OPERAND_FAIL;
}
else if (skip_past_char (&p, ':') == SUCCESS)
- {
- /* FIXME: '@' should be used here, but it's filtered out by generic
- code before we get to see it here. This may be subject to
- change. */
- expressionS exp;
- my_get_expression (&exp, &p, GE_NO_PREFIX);
- if (exp.X_op != O_constant)
- {
- inst.error = _("alignment must be constant");
- return PARSE_OPERAND_FAIL;
- }
- inst.operands[i].imm = exp.X_add_number << 8;
- inst.operands[i].immisalign = 1;
- /* Alignments are not pre-indexes. */
- inst.operands[i].preind = 0;
- }
+ {
+ /* FIXME: '@' should be used here, but it's filtered out by generic
+ code before we get to see it here. This may be subject to
+ change. */
+ parse_operand_result result = parse_neon_alignment (&p, i);
+
+ if (result != PARSE_OPERAND_SUCCESS)
+ return result;
+ }
else
{
if (inst.operands[i].negative)
return PARSE_OPERAND_FAIL;
}
}
+ else if (skip_past_char (&p, ':') == SUCCESS)
+ {
+ /* FIXME: '@' should be used here, but it's filtered out by generic code
+ before we get to see it here. This may be subject to change. */
+ parse_operand_result result = parse_neon_alignment (&p, i);
+
+ if (result != PARSE_OPERAND_SUCCESS)
+ return result;
+ }
if (skip_past_char (&p, ']') == FAIL)
{
OP_RRnpc, /* ARM register, not r15 */
OP_RRnpcsp, /* ARM register, neither r15 nor r13 (a.k.a. 'BadReg') */
OP_RRnpcb, /* ARM register, not r15, in square brackets */
+ OP_RRnpctw, /* ARM register, not r15 in Thumb-state or with writeback,
+ optional trailing ! */
OP_RRw, /* ARM register, not r15, optional trailing ! */
OP_RCP, /* Coprocessor number */
OP_RCN, /* Coprocessor register */
po_char_or_fail (']');
break;
+ case OP_RRnpctw:
case OP_RRw:
case OP_oRRw:
po_reg_or_fail (REG_TYPE_RN);
}
break;
+ case OP_RRnpctw:
+ if (inst.operands[i].isreg
+ && inst.operands[i].reg == REG_PC
+ && (inst.operands[i].writeback || thumb))
+ inst.error = BAD_PC;
+ break;
+
case OP_CPSF:
case OP_ENDI:
case OP_oROR:
if (mask & (1 << 13))
inst.error = _("SP not allowed in register list");
+
+ if ((mask & (1 << base)) != 0
+ && writeback)
+ inst.error = _("having the base register in the register list when "
+ "using write back is UNPREDICTABLE");
+
if (load)
{
if (mask & (1 << 15))
else
set_it_insn_type_last ();
}
-
- if ((mask & (1 << base)) != 0
- && writeback)
- as_warn (_("base register should not be in register list "
- "when written back"));
}
else
{
if (mask & (1 << 15))
inst.error = _("PC not allowed in register list");
-
- if (mask & (1 << base))
- as_warn (_("value stored for r%d is UNPREDICTABLE"), base);
}
if ((mask & (mask - 1)) == 0)
if (inst.instruction == T_MNEM_stmia
&& (inst.operands[1].imm & mask)
&& (inst.operands[1].imm & (mask - 1)))
- as_warn (_("value stored for r%d is UNPREDICTABLE"),
+ as_warn (_("value stored for r%d is UNKNOWN"),
inst.operands[0].reg);
inst.instruction = THUMB_OP16 (inst.instruction);
as_warn (_("this instruction will write back the base register"));
if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
&& (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
- as_warn (_("value stored for r%d is UNPREDICTABLE"),
+ as_warn (_("value stored for r%d is UNKNOWN"),
inst.operands[0].reg);
}
else
case T_MNEM_movs:
/* We know we have low registers at this point.
- Generate ADD Rd, Rs, #0. */
- inst.instruction = T_OPCODE_ADD_I3;
+ Generate LSLS Rd, Rs, #0. */
+ inst.instruction = T_OPCODE_LSL_I;
inst.instruction |= Rn;
inst.instruction |= Rm << 3;
break;
|| (thumb_mode == 1
&& !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
{
- as_bad (_("selected processor does not support `%s'"), str);
+ as_bad (_("selected processor does not support Thumb mode `%s'"), str);
return;
}
if (inst.cond != COND_ALWAYS && !unified_syntax
inst.size_req = 2;
else if (inst.size_req == 4)
{
- as_bad (_("selected processor does not support `%s'"), str);
+ as_bad (_("selected processor does not support Thumb-2 mode `%s'"), str);
return;
}
}
&& !(opcode->avariant &&
ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant)))
{
- as_bad (_("selected processor does not support `%s'"), str);
+ as_bad (_("selected processor does not support ARM mode `%s'"), str);
return;
}
if (inst.size_req)
#define do_0 0
-/* Thumb-only, unconditional. */
-#define UT(mnem, op, nops, ops, te) TUE (mnem, 0, op, nops, ops, 0, te)
-
static const struct asm_opcode insns[] =
{
#define ARM_VARIANT &arm_ext_v1 /* Core ARM Instructions. */
TC3("ldrsbt", 03000d0, f9100e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
TC3("strht", 02000b0, f8200e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
- UT("cbnz", b900, 2, (RR, EXP), t_cbz),
- UT("cbz", b100, 2, (RR, EXP), t_cbz),
+ /* Thumb-only instructions. */
+#undef ARM_VARIANT
+#define ARM_VARIANT NULL
+ TUE("cbnz", 0, b900, 2, (RR, EXP), 0, t_cbz),
+ TUE("cbz", 0, b100, 2, (RR, EXP), 0, t_cbz),
/* ARM does not really have an IT instruction, so always allow it.
The opcode is copied from Thumb in order to allow warnings in
/* Memory operations. */
cCE("flds", d100a00, 2, (RVS, ADDRGLDC), vfp_sp_ldst),
cCE("fsts", d000a00, 2, (RVS, ADDRGLDC), vfp_sp_ldst),
- cCE("fldmias", c900a00, 2, (RRw, VRSLST), vfp_sp_ldstmia),
- cCE("fldmfds", c900a00, 2, (RRw, VRSLST), vfp_sp_ldstmia),
- cCE("fldmdbs", d300a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb),
- cCE("fldmeas", d300a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb),
- cCE("fldmiax", c900b00, 2, (RRw, VRDLST), vfp_xp_ldstmia),
- cCE("fldmfdx", c900b00, 2, (RRw, VRDLST), vfp_xp_ldstmia),
- cCE("fldmdbx", d300b00, 2, (RRw, VRDLST), vfp_xp_ldstmdb),
- cCE("fldmeax", d300b00, 2, (RRw, VRDLST), vfp_xp_ldstmdb),
- cCE("fstmias", c800a00, 2, (RRw, VRSLST), vfp_sp_ldstmia),
- cCE("fstmeas", c800a00, 2, (RRw, VRSLST), vfp_sp_ldstmia),
- cCE("fstmdbs", d200a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb),
- cCE("fstmfds", d200a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb),
- cCE("fstmiax", c800b00, 2, (RRw, VRDLST), vfp_xp_ldstmia),
- cCE("fstmeax", c800b00, 2, (RRw, VRDLST), vfp_xp_ldstmia),
- cCE("fstmdbx", d200b00, 2, (RRw, VRDLST), vfp_xp_ldstmdb),
- cCE("fstmfdx", d200b00, 2, (RRw, VRDLST), vfp_xp_ldstmdb),
+ cCE("fldmias", c900a00, 2, (RRnpctw, VRSLST), vfp_sp_ldstmia),
+ cCE("fldmfds", c900a00, 2, (RRnpctw, VRSLST), vfp_sp_ldstmia),
+ cCE("fldmdbs", d300a00, 2, (RRnpctw, VRSLST), vfp_sp_ldstmdb),
+ cCE("fldmeas", d300a00, 2, (RRnpctw, VRSLST), vfp_sp_ldstmdb),
+ cCE("fldmiax", c900b00, 2, (RRnpctw, VRDLST), vfp_xp_ldstmia),
+ cCE("fldmfdx", c900b00, 2, (RRnpctw, VRDLST), vfp_xp_ldstmia),
+ cCE("fldmdbx", d300b00, 2, (RRnpctw, VRDLST), vfp_xp_ldstmdb),
+ cCE("fldmeax", d300b00, 2, (RRnpctw, VRDLST), vfp_xp_ldstmdb),
+ cCE("fstmias", c800a00, 2, (RRnpctw, VRSLST), vfp_sp_ldstmia),
+ cCE("fstmeas", c800a00, 2, (RRnpctw, VRSLST), vfp_sp_ldstmia),
+ cCE("fstmdbs", d200a00, 2, (RRnpctw, VRSLST), vfp_sp_ldstmdb),
+ cCE("fstmfds", d200a00, 2, (RRnpctw, VRSLST), vfp_sp_ldstmdb),
+ cCE("fstmiax", c800b00, 2, (RRnpctw, VRDLST), vfp_xp_ldstmia),
+ cCE("fstmeax", c800b00, 2, (RRnpctw, VRDLST), vfp_xp_ldstmia),
+ cCE("fstmdbx", d200b00, 2, (RRnpctw, VRDLST), vfp_xp_ldstmdb),
+ cCE("fstmfdx", d200b00, 2, (RRnpctw, VRDLST), vfp_xp_ldstmdb),
/* Monadic operations. */
cCE("fabss", eb00ac0, 2, (RVS, RVS), vfp_sp_monadic),
implementations. */
cCE("fldd", d100b00, 2, (RVD, ADDRGLDC), vfp_dp_ldst),
cCE("fstd", d000b00, 2, (RVD, ADDRGLDC), vfp_dp_ldst),
- cCE("fldmiad", c900b00, 2, (RRw, VRDLST), vfp_dp_ldstmia),
- cCE("fldmfdd", c900b00, 2, (RRw, VRDLST), vfp_dp_ldstmia),
- cCE("fldmdbd", d300b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb),
- cCE("fldmead", d300b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb),
- cCE("fstmiad", c800b00, 2, (RRw, VRDLST), vfp_dp_ldstmia),
- cCE("fstmead", c800b00, 2, (RRw, VRDLST), vfp_dp_ldstmia),
- cCE("fstmdbd", d200b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb),
- cCE("fstmfdd", d200b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb),
+ cCE("fldmiad", c900b00, 2, (RRnpctw, VRDLST), vfp_dp_ldstmia),
+ cCE("fldmfdd", c900b00, 2, (RRnpctw, VRDLST), vfp_dp_ldstmia),
+ cCE("fldmdbd", d300b00, 2, (RRnpctw, VRDLST), vfp_dp_ldstmdb),
+ cCE("fldmead", d300b00, 2, (RRnpctw, VRDLST), vfp_dp_ldstmdb),
+ cCE("fstmiad", c800b00, 2, (RRnpctw, VRDLST), vfp_dp_ldstmia),
+ cCE("fstmead", c800b00, 2, (RRnpctw, VRDLST), vfp_dp_ldstmia),
+ cCE("fstmdbd", d200b00, 2, (RRnpctw, VRDLST), vfp_dp_ldstmdb),
+ cCE("fstmfdd", d200b00, 2, (RRnpctw, VRDLST), vfp_dp_ldstmdb),
#undef ARM_VARIANT
#define ARM_VARIANT & fpu_vfp_ext_v1 /* VFP V1 (Double precision). */
NCEF(vabs, 1b10300, 2, (RNSDQ, RNSDQ), neon_abs_neg),
NCEF(vneg, 1b10380, 2, (RNSDQ, RNSDQ), neon_abs_neg),
- NCE(vldm, c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vldmia, c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vldmdb, d100b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vstm, c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vstmia, c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vstmdb, d000b00, 2, (RRw, VRSDLST), neon_ldm_stm),
+ NCE(vldm, c900b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vldmia, c900b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vldmdb, d100b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vstm, c800b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vstmia, c800b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vstmdb, d000b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
NCE(vldr, d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
NCE(vstr, d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
/* Assume worst case for symbols not known to be in the same section. */
if (fragp->fr_symbol == NULL
|| !S_IS_DEFINED (fragp->fr_symbol)
- || sec != S_GET_SEGMENT (fragp->fr_symbol))
+ || sec != S_GET_SEGMENT (fragp->fr_symbol)
+ || S_IS_WEAK (fragp->fr_symbol))
return 4;
val = relaxed_symbol_addr (fragp, stretch);
/* Assume worst case for symbols not known to be in the same section. */
if (!S_IS_DEFINED (fragp->fr_symbol)
- || sec != S_GET_SEGMENT (fragp->fr_symbol))
+ || sec != S_GET_SEGMENT (fragp->fr_symbol)
+ || S_IS_WEAK (fragp->fr_symbol))
return 4;
#ifdef OBJ_ELF
not have a reloc for it, so tc_gen_reloc will reject it. */
fixP->fx_done = 1;
- if (fixP->fx_addsy
- && ! S_IS_DEFINED (fixP->fx_addsy))
+ if (fixP->fx_addsy)
{
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("undefined symbol %s used as an immediate value"),
- S_GET_NAME (fixP->fx_addsy));
- break;
- }
+ const char *msg = 0;
- if (fixP->fx_addsy
- && S_GET_SEGMENT (fixP->fx_addsy) != seg)
- {
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("symbol %s is in a different section"),
- S_GET_NAME (fixP->fx_addsy));
- break;
+ if (! S_IS_DEFINED (fixP->fx_addsy))
+ msg = _("undefined symbol %s used as an immediate value");
+ else if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
+ msg = _("symbol %s is in a different section");
+ else if (S_IS_WEAK (fixP->fx_addsy))
+ msg = _("symbol %s is weak and may be overridden later");
+
+ if (msg)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ msg, S_GET_NAME (fixP->fx_addsy));
+ break;
+ }
}
newimm = encode_arm_immediate (value);
unsigned int highpart = 0;
unsigned int newinsn = 0xe1a00000; /* nop. */
- if (fixP->fx_addsy
- && ! S_IS_DEFINED (fixP->fx_addsy))
+ if (fixP->fx_addsy)
{
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("undefined symbol %s used as an immediate value"),
- S_GET_NAME (fixP->fx_addsy));
- break;
- }
+ const char *msg = 0;
- if (fixP->fx_addsy
- && S_GET_SEGMENT (fixP->fx_addsy) != seg)
- {
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("symbol %s is in a different section"),
- S_GET_NAME (fixP->fx_addsy));
- break;
- }
+ if (! S_IS_DEFINED (fixP->fx_addsy))
+ msg = _("undefined symbol %s used as an immediate value");
+ else if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
+ msg = _("symbol %s is in a different section");
+ else if (S_IS_WEAK (fixP->fx_addsy))
+ msg = _("symbol %s is weak and may be overridden later");
+ if (msg)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ msg, S_GET_NAME (fixP->fx_addsy));
+ break;
+ }
+ }
+
newimm = encode_arm_immediate (value);
temp = md_chars_to_number (buf, INSN_SIZE);
|| ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1xd))
aeabi_set_attribute_int (Tag_VFP_arch, 1);
+ /* Tag_ABI_HardFP_use. */
+ if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1xd)
+ && !ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1))
+ aeabi_set_attribute_int (Tag_ABI_HardFP_use, 1);
+
/* Tag_WMMX_arch. */
if (ARM_CPU_HAS_FEATURE (flags, arm_cext_iwmmxt2))
aeabi_set_attribute_int (Tag_WMMX_arch, 2);
/* Tag_VFP_HP_extension (formerly Tag_NEON_FP16_arch). */
if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16))
aeabi_set_attribute_int (Tag_VFP_HP_extension, 1);
+
+ /* Tag_DIV_use. */
+ if (ARM_CPU_HAS_FEATURE (flags, arm_ext_div))
+ aeabi_set_attribute_int (Tag_DIV_use, 0);
+ /* Fill this in when gas supports v7a sdiv/udiv.
+ else if (... v7a with div extension used ...)
+ aeabi_set_attribute_int (Tag_DIV_use, 2); */
+ else
+ aeabi_set_attribute_int (Tag_DIV_use, 1);
}
/* Add the default contents for the .ARM.attributes section. */