static const arm_feature_set arm_ext_os = ARM_FEATURE_CORE_LOW (ARM_EXT_OS);
static const arm_feature_set arm_ext_adiv = ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV);
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_arch_any = ARM_ANY;
static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1, -1);
ARM_FEATURE_COPROC (FPU_CRYPTO_EXT_ARMV8);
static const arm_feature_set crc_ext_armv8 =
ARM_FEATURE_COPROC (CRC_EXT_ARMV8);
+static const arm_feature_set fpu_neon_ext_v8_1 =
+ ARM_FEATURE_COPROC (FPU_NEON_EXT_ARMV8 | FPU_NEON_EXT_RDMA);
static int mfloat_abi_opt = -1;
/* Record user cpu selection for object attributes. */
static arm_feature_set selected_cpu = ARM_ARCH_NONE;
/* Must be long enough to hold any of the names in arm_cpus. */
-static char selected_cpu_name[16];
+static char selected_cpu_name[20];
extern FLONUM_TYPE generic_floating_point_number;
/* Especial apologies for the random logic:
This just grew, and could be parsed much more simply!
Dean - in haste. */
- name = input_line_pointer;
- delim = get_symbol_end ();
+ delim = get_symbol_name (& name);
end_name = input_line_pointer;
- *end_name = delim;
+ (void) restore_line_pointer (delim);
if (*input_line_pointer != ',')
{
{
char *name, delim;
- name = input_line_pointer;
- delim = get_symbol_end ();
+ delim = get_symbol_name (& name);
if (!strcasecmp (name, "unified"))
unified_syntax = TRUE;
as_bad (_("unrecognized syntax mode \"%s\""), name);
return;
}
- *input_line_pointer = delim;
+ (void) restore_line_pointer (delim);
demand_empty_rest_of_line ();
}
/* Directives: sectioning and alignment. */
-/* Same as s_align_ptwo but align 0 => align 2. */
-
-static void
-s_align (int unused ATTRIBUTE_UNUSED)
-{
- int temp;
- bfd_boolean fill_p;
- long temp_fill;
- long max_alignment = 15;
-
- temp = get_absolute_expression ();
- if (temp > max_alignment)
- as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
- else if (temp < 0)
- {
- as_bad (_("alignment negative. 0 assumed."));
- temp = 0;
- }
-
- if (*input_line_pointer == ',')
- {
- input_line_pointer++;
- temp_fill = get_absolute_expression ();
- fill_p = TRUE;
- }
- else
- {
- fill_p = FALSE;
- temp_fill = 0;
- }
-
- if (!temp)
- temp = 2;
-
- /* Only make a frag if we HAVE to. */
- if (temp && !need_pass_2)
- {
- if (!fill_p && subseg_text_p (now_seg))
- frag_align_code (temp, 0);
- else
- frag_align (temp, (int) temp_fill, 0);
- }
- demand_empty_rest_of_line ();
-
- record_alignment (now_seg, temp);
-}
-
static void
s_bss (int ignore ATTRIBUTE_UNUSED)
{
}
bfd_boolean
-tc_start_label_without_colon (char unused1 ATTRIBUTE_UNUSED, const char * rest)
+tc_start_label_without_colon (void)
{
bfd_boolean ret = TRUE;
if (codecomposer_syntax && asmfunc_state == WAITING_ASMFUNC_NAME)
{
- const char *label = rest;
+ const char *label = input_line_pointer;
while (!is_end_of_line[(int) label[-1]])
--label;
if (unwind.personality_routine || unwind.personality_index != -1)
as_bad (_("duplicate .personality directive"));
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (& name);
p = input_line_pointer;
+ if (c == '"')
+ ++ input_line_pointer;
unwind.personality_routine = symbol_find_or_make (name);
*p = c;
demand_empty_rest_of_line ();
{ "qn", s_qn, 0 },
{ "unreq", s_unreq, 0 },
{ "bss", s_bss, 0 },
- { "align", s_align, 0 },
+ { "align", s_align_ptwo, 2 },
{ "arm", s_arm, 0 },
{ "thumb", s_thumb, 0 },
{ "code", s_code, 0 },
{
/* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
Ditto for 15. */
- if (gen_to_words (words, 5, (long) 15) == 0)
+#define X_PRECISION 5
+#define E_PRECISION 15L
+ if (gen_to_words (words, X_PRECISION, E_PRECISION) == 0)
{
for (i = 0; i < NUM_FLOAT_VALS; i++)
{
return FAIL;
}
+#if defined BFD_HOST_64_BIT
+/* Returns TRUE if double precision value V may be cast
+ to single precision without loss of accuracy. */
+
+static bfd_boolean
+is_double_a_single (bfd_int64_t v)
+{
+ int exp = (int)((v >> 52) & 0x7FF);
+ bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFFULL);
+
+ return (exp == 0 || exp == 0x7FF
+ || (exp >= 1023 - 126 && exp <= 1023 + 127))
+ && (mantissa & 0x1FFFFFFFl) == 0;
+}
+
+/* Returns a double precision value casted to single precision
+ (ignoring the least significant bits in exponent and mantissa). */
+
+static int
+double_to_single (bfd_int64_t v)
+{
+ int sign = (int) ((v >> 63) & 1l);
+ int exp = (int) ((v >> 52) & 0x7FF);
+ bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFFULL);
+
+ if (exp == 0x7FF)
+ exp = 0xFF;
+ else
+ {
+ exp = exp - 1023 + 127;
+ if (exp >= 0xFF)
+ {
+ /* Infinity. */
+ exp = 0x7F;
+ mantissa = 0;
+ }
+ else if (exp < 0)
+ {
+ /* No denormalized numbers. */
+ exp = 0;
+ mantissa = 0;
+ }
+ }
+ mantissa >>= 29;
+ return (sign << 31) | (exp << 23) | mantissa;
+}
+#endif /* BFD_HOST_64_BIT */
+
enum lit_type
{
CONST_THUMB,
CONST_VEC
};
+static void do_vfp_nsyn_opcode (const char *);
+
/* inst.reloc.exp describes an "=expr" load pseudo-operation.
Determine whether it can be performed with a move instruction; if
it can, convert inst.instruction to that move instruction and
unsigned long tbit;
bfd_boolean thumb_p = (t == CONST_THUMB);
bfd_boolean arm_p = (t == CONST_ARM);
- bfd_boolean vec64_p = (t == CONST_VEC) && !inst.operands[i].issingle;
if (thumb_p)
tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT;
inst.error = _("invalid pseudo operation");
return TRUE;
}
+
if (inst.reloc.exp.X_op != O_constant
&& inst.reloc.exp.X_op != O_symbol
&& inst.reloc.exp.X_op != O_big)
inst.error = _("constant expression expected");
return TRUE;
}
- if ((inst.reloc.exp.X_op == O_constant
- || inst.reloc.exp.X_op == O_big)
- && !inst.operands[i].issingle)
+
+ if (inst.reloc.exp.X_op == O_constant
+ || inst.reloc.exp.X_op == O_big)
{
- if (thumb_p && inst.reloc.exp.X_op == O_constant)
+#if defined BFD_HOST_64_BIT
+ bfd_int64_t v;
+#else
+ offsetT v;
+#endif
+ if (inst.reloc.exp.X_op == O_big)
{
- if (!unified_syntax && (inst.reloc.exp.X_add_number & ~0xFF) == 0)
+ LITTLENUM_TYPE w[X_PRECISION];
+ LITTLENUM_TYPE * l;
+
+ if (inst.reloc.exp.X_add_number == -1)
{
- /* This can be done with a mov(1) instruction. */
- inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
- inst.instruction |= inst.reloc.exp.X_add_number;
- return TRUE;
+ gen_to_words (w, X_PRECISION, E_PRECISION);
+ l = w;
+ /* FIXME: Should we check words w[2..5] ? */
}
+ else
+ l = generic_bignum;
+
+#if defined BFD_HOST_64_BIT
+ v =
+ ((((((((bfd_int64_t) l[3] & LITTLENUM_MASK)
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((bfd_int64_t) l[2] & LITTLENUM_MASK))
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((bfd_int64_t) l[1] & LITTLENUM_MASK))
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((bfd_int64_t) l[0] & LITTLENUM_MASK));
+#else
+ v = ((l[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
+ | (l[0] & LITTLENUM_MASK);
+#endif
}
- else if (arm_p && inst.reloc.exp.X_op == O_constant)
+ else
+ v = inst.reloc.exp.X_add_number;
+
+ if (!inst.operands[i].issingle)
{
- int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
- if (value != FAIL)
+ if (thumb_p)
{
- /* This can be done with a mov instruction. */
- inst.instruction &= LITERAL_MASK;
- inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
- inst.instruction |= value & 0xfff;
- return TRUE;
+ if ((v & ~0xFF) == 0)
+ {
+ /* This can be done with a mov(1) instruction. */
+ inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
+ inst.instruction |= v;
+ return TRUE;
+ }
+
+ if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2))
+ {
+ /* Check if on thumb2 it can be done with a mov.w or mvn.w
+ instruction. */
+ unsigned int newimm;
+ bfd_boolean isNegated;
+
+ newimm = encode_thumb32_immediate (v);
+ if (newimm != (unsigned int) FAIL)
+ isNegated = FALSE;
+ else
+ {
+ newimm = encode_thumb32_immediate (~v);
+ if (newimm != (unsigned int) FAIL)
+ isNegated = TRUE;
+ }
+
+ if (newimm != (unsigned int) FAIL)
+ {
+ inst.instruction = (0xf04f0000
+ | (inst.operands[i].reg << 8));
+ inst.instruction |= (isNegated ? 0x200000 : 0);
+ inst.instruction |= (newimm & 0x800) << 15;
+ inst.instruction |= (newimm & 0x700) << 4;
+ inst.instruction |= (newimm & 0x0ff);
+ return TRUE;
+ }
+ else if ((v & ~0xFFFF) == 0)
+ {
+ /* The number can be loaded with a mov.w instruction. */
+ int imm = v & 0xFFFF;
+
+ inst.instruction = 0xf2400000; /* MOVW. */
+ inst.instruction |= (inst.operands[i].reg << 8);
+ inst.instruction |= (imm & 0xf000) << 4;
+ inst.instruction |= (imm & 0x0800) << 15;
+ inst.instruction |= (imm & 0x0700) << 4;
+ inst.instruction |= (imm & 0x00ff);
+ return TRUE;
+ }
+ }
}
+ else if (arm_p)
+ {
+ int value = encode_arm_immediate (v);
- value = encode_arm_immediate (~inst.reloc.exp.X_add_number);
- if (value != FAIL)
+ if (value != FAIL)
+ {
+ /* This can be done with a mov instruction. */
+ inst.instruction &= LITERAL_MASK;
+ inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
+ inst.instruction |= value & 0xfff;
+ return TRUE;
+ }
+
+ value = encode_arm_immediate (~ v);
+ if (value != FAIL)
+ {
+ /* This can be done with a mvn instruction. */
+ inst.instruction &= LITERAL_MASK;
+ inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
+ inst.instruction |= value & 0xfff;
+ return TRUE;
+ }
+ }
+ else if (t == CONST_VEC)
{
- /* This can be done with a mvn instruction. */
- inst.instruction &= LITERAL_MASK;
- inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
- inst.instruction |= value & 0xfff;
- return TRUE;
+ int op = 0;
+ unsigned immbits = 0;
+ unsigned immlo = inst.operands[1].imm;
+ unsigned immhi = inst.operands[1].regisimm
+ ? inst.operands[1].reg
+ : inst.reloc.exp.X_unsigned
+ ? 0
+ : ((bfd_int64_t)((int) immlo)) >> 32;
+ int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
+ &op, 64, NT_invtype);
+
+ if (cmode == FAIL)
+ {
+ neon_invert_size (&immlo, &immhi, 64);
+ op = !op;
+ cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
+ &op, 64, NT_invtype);
+ }
+
+ if (cmode != FAIL)
+ {
+ inst.instruction = (inst.instruction & VLDR_VMOV_SAME)
+ | (1 << 23)
+ | (cmode << 8)
+ | (op << 5)
+ | (1 << 4);
+
+ /* Fill other bits in vmov encoding for both thumb and arm. */
+ if (thumb_mode)
+ inst.instruction |= (0x7U << 29) | (0xF << 24);
+ else
+ inst.instruction |= (0xFU << 28) | (0x1 << 25);
+ neon_write_immbits (immbits);
+ return TRUE;
+ }
}
}
- else if (vec64_p)
- {
- int op = 0;
- unsigned immbits = 0;
- unsigned immlo = inst.operands[1].imm;
- unsigned immhi = inst.operands[1].regisimm
- ? inst.operands[1].reg
- : inst.reloc.exp.X_unsigned
- ? 0
- : ((bfd_int64_t)((int) immlo)) >> 32;
- int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
- &op, 64, NT_invtype);
- if (cmode == FAIL)
+ if (t == CONST_VEC)
+ {
+ /* Check if vldr Rx, =constant could be optimized to vmov Rx, #constant. */
+ if (inst.operands[i].issingle
+ && is_quarter_float (inst.operands[1].imm)
+ && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3xd))
{
- neon_invert_size (&immlo, &immhi, 64);
- op = !op;
- cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
- &op, 64, NT_invtype);
+ inst.operands[1].imm =
+ neon_qfloat_bits (v);
+ do_vfp_nsyn_opcode ("fconsts");
+ return TRUE;
}
- if (cmode != FAIL)
+
+ /* If our host does not support a 64-bit type then we cannot perform
+ the following optimization. This mean that there will be a
+ discrepancy between the output produced by an assembler built for
+ a 32-bit-only host and the output produced from a 64-bit host, but
+ this cannot be helped. */
+#if defined BFD_HOST_64_BIT
+ else if (!inst.operands[1].issingle
+ && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
{
- inst.instruction = (inst.instruction & VLDR_VMOV_SAME)
- | (1 << 23)
- | (cmode << 8)
- | (op << 5)
- | (1 << 4);
- /* Fill other bits in vmov encoding for both thumb and arm. */
- if (thumb_mode)
- inst.instruction |= (0x7 << 29) | (0xF << 24);
- else
- inst.instruction |= (0xF << 28) | (0x1 << 25);
- neon_write_immbits (immbits);
- return TRUE;
+ if (is_double_a_single (v)
+ && is_quarter_float (double_to_single (v)))
+ {
+ inst.operands[1].imm =
+ neon_qfloat_bits (double_to_single (v));
+ do_vfp_nsyn_opcode ("fconstd");
+ return TRUE;
+ }
}
+#endif
}
}
{
if (!inst.operands[i].isreg)
{
- gas_assert (inst.operands[0].isvec);
+ /* PR 18256 */
+ if (! inst.operands[0].isvec)
+ {
+ inst.error = _("invalid co-processor operand");
+ return FAIL;
+ }
if (move_or_literal_pool (0, CONST_VEC, /*mode_3=*/FALSE))
return SUCCESS;
}
}
}
-static void do_vfp_nsyn_opcode (const char *);
-
static int
do_vfp_nsyn_mrs (void)
{
inst.reloc.pc_rel = 0;
}
+static void
+do_setpan (void)
+{
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_pan),
+ _("selected processor does not support SETPAN instruction"));
+
+ inst.instruction |= ((inst.operands[0].imm & 1) << 9);
+}
+
+static void
+do_t_setpan (void)
+{
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_pan),
+ _("selected processor does not support SETPAN instruction"));
+
+ inst.instruction |= (inst.operands[0].imm << 3);
+}
+
/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
SMLAxy{cond} Rd,Rm,Rs,Rn
SMLAWy{cond} Rd,Rm,Rs,Rn
&& inst.operands[1].immisreg)
{
inst.instruction &= ~0x1a000ff;
- inst.instruction |= (0xf << 28);
+ inst.instruction |= (0xfU << 28);
if (inst.operands[1].preind)
inst.instruction |= PRE_INDEX;
if (!inst.operands[1].negative)
}
/* Map 32 -> 0, etc. */
inst.operands[2].imm &= 0x1f;
- inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
+ inst.instruction |= (0xfU << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
}
}
\f
X(vqdmull, 0x0800d00, N_INV, 0x0800b40), \
X(vqdmulh, 0x0000b00, N_INV, 0x0800c40), \
X(vqrdmulh, 0x1000b00, N_INV, 0x0800d40), \
+ X(vqrdmlah, 0x3000b10, N_INV, 0x0800e40), \
+ X(vqrdmlsh, 0x3000c10, N_INV, 0x0800f40), \
X(vshl, 0x0000400, N_INV, 0x0800510), \
X(vqshl, 0x0000410, N_INV, 0x0800710), \
X(vand, 0x0000110, N_INV, 0x0800030), \
|| (thumb_mode == 1
&& !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
{
- as_bad (_("selected processor does not support Thumb mode `%s'"), str);
+ as_bad (_("selected processor does not support `%s' in Thumb mode"), 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 Thumb-2 mode `%s'"), str);
+ as_bad (_("selected processor does not support `%s' in Thumb-2 mode"), str);
return;
}
}
&& !(opcode->avariant &&
ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant)))
{
- as_bad (_("selected processor does not support ARM mode `%s'"), str);
+ as_bad (_("selected processor does not support `%s' in ARM mode"), str);
return;
}
if (inst.size_req)
inst.instruction = opcode->avalue;
if (opcode->tag == OT_unconditionalF)
- inst.instruction |= 0xF << 28;
+ inst.instruction |= 0xFU << 28;
else
inst.instruction |= inst.cond << 28;
inst.size = INSN_SIZE;
UF(srsed, 8400500, 2, (oRRw, I31w), srs),
TUF("srsdb", 9400500, e800c000, 2, (oRRw, I31w), srs, srs),
TUF("srsfd", 9400500, e800c000, 2, (oRRw, I31w), srs, srs),
+ TUF("cps", 1020000, f3af8100, 1, (I31b), imm0, t_cps),
/* ARM V6 not included in V7M (eg. integer SIMD). */
#undef THUMB_VARIANT
#define THUMB_VARIANT & arm_ext_v6_dsp
- TUF("cps", 1020000, f3af8100, 1, (I31b), imm0, t_cps),
TCE("pkhbt", 6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll), pkhbt, t_pkhbt),
TCE("pkhtb", 6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar), pkhtb, t_pkhtb),
TCE("qadd16", 6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd),
TCE("hvc", 1400070, f7e08000, 1, (EXPi), hvc, t_hvc),
TCE("eret", 160006e, f3de8f00, 0, (), noargs, noargs),
+#undef ARM_VARIANT
+#define ARM_VARIANT & arm_ext_pan
+#undef THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_pan
+
+ TUF("setpan", 1100000, b610, 1, (I7), setpan, t_setpan),
+
#undef ARM_VARIANT
#define ARM_VARIANT & arm_ext_v6t2
#undef THUMB_VARIANT
NUF(vrecpsq, 0000f10, 3, (RNQ, oRNQ, RNQ), neon_step),
NUF(vrsqrts, 0200f10, 3, (RNDQ, oRNDQ, RNDQ), neon_step),
NUF(vrsqrtsq, 0200f10, 3, (RNQ, oRNQ, RNQ), neon_step),
+ /* ARM v8.1 extension. */
+ nUF(vqrdmlah, _vqrdmlah, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
+ nUF(vqrdmlahq, _vqrdmlah, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_qdmulh),
+ nUF(vqrdmlsh, _vqrdmlsh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
+ nUF(vqrdmlshq, _vqrdmlsh, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_qdmulh),
/* Two address, int/float. Types S8 S16 S32 F32. */
NUF(vabsq, 1b10300, 2, (RNQ, RNQ), neon_abs_neg),
int align;
align = bfd_get_section_alignment (stdoutput, segment);
- size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
+ size = ((size + (1 << align) - 1) & (-((valueT) 1 << align)));
}
#endif
void
arm_init_frag (fragS * fragP, int max_chars)
{
+ int frag_thumb_mode;
+
/* If the current ARM vs THUMB mode has not already
been recorded into this frag then do so now. */
if ((fragP->tc_frag_data.thumb_mode & MODE_RECORDED) == 0)
- fragP->tc_frag_data.thumb_mode = thumb_mode | MODE_RECORDED;
+ fragP->tc_frag_data.thumb_mode = thumb_mode | MODE_RECORDED;
+
+ frag_thumb_mode = fragP->tc_frag_data.thumb_mode ^ MODE_RECORDED;
/* Record a mapping symbol for alignment frags. We will delete this
later if the alignment ends up empty. */
mapping_state_2 (MAP_DATA, max_chars);
break;
case rs_align_code:
- mapping_state_2 (thumb_mode ? MAP_THUMB : MAP_ARM, max_chars);
+ mapping_state_2 (frag_thumb_mode ? MAP_THUMB : MAP_ARM, max_chars);
break;
default:
break;
}
}
+static bfd_boolean flag_warn_syms = TRUE;
+
+bfd_boolean
+arm_tc_equal_in_insn (int c ATTRIBUTE_UNUSED, char * name)
+{
+ /* PR 18347 - Warn if the user attempts to create a symbol with the same
+ name as an ARM instruction. Whilst strictly speaking it is allowed, it
+ does mean that the resulting code might be very confusing to the reader.
+ Also this warning can be triggered if the user omits an operand before
+ an immediate address, eg:
+
+ LDR =foo
+
+ GAS treats this as an assignment of the value of the symbol foo to a
+ symbol LDR, and so (without this code) it will not issue any kind of
+ warning or error message.
+
+ Note - ARM instructions are case-insensitive but the strings in the hash
+ table are all stored in lower case, so we must first ensure that name is
+ lower case too. */
+ if (flag_warn_syms && arm_ops_hsh)
+ {
+ char * nbuf = strdup (name);
+ char * p;
+
+ for (p = nbuf; *p; p++)
+ *p = TOLOWER (*p);
+ if (hash_find (arm_ops_hsh, nbuf) != NULL)
+ {
+ static struct hash_control * already_warned = NULL;
+
+ if (already_warned == NULL)
+ already_warned = hash_new ();
+ /* Only warn about the symbol once. To keep the code
+ simple we let hash_insert do the lookup for us. */
+ if (hash_insert (already_warned, name, NULL) == NULL)
+ as_warn (_("[-mwarn-syms]: Assignment makes a symbol match an ARM instruction: %s"), name);
+ }
+ else
+ free (nbuf);
+ }
+
+ return FALSE;
+}
+
/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
Otherwise we have no need to default values of symbols. */
if (rd == REG_SP)
{
- if (value & ~0x1fc)
+ if (value & ~0x1fc)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("invalid immediate for stack address calculation"));
newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
}
else if (rs == REG_PC || rs == REG_SP)
{
+ /* PR gas/18541. If the addition is for a defined symbol
+ within range of an ADR instruction then accept it. */
+ if (subtract
+ && value == 4
+ && fixP->fx_addsy != NULL)
+ {
+ subtract = 0;
+
+ if (! S_IS_DEFINED (fixP->fx_addsy)
+ || S_GET_SEGMENT (fixP->fx_addsy) != seg
+ || S_IS_WEAK (fixP->fx_addsy))
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("address calculation needs a strongly defined nearby symbol"));
+ }
+ else
+ {
+ offsetT v = fixP->fx_where + fixP->fx_frag->fr_address;
+
+ /* Round up to the next 4-byte boundary. */
+ if (v & 3)
+ v = (v + 3) & ~ 3;
+ else
+ v += 4;
+ v = S_GET_VALUE (fixP->fx_addsy) - v;
+
+ if (v & ~0x3fc)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("symbol too far away"));
+ }
+ else
+ {
+ fixP->fx_done = 1;
+ value = v;
+ }
+ }
+ }
+
if (subtract || value & ~0x3fc)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("invalid immediate for address calculation (value = 0x%08lX)"),
- (unsigned long) value);
+ (unsigned long) (subtract ? - value : value));
newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
newval |= rd << 8;
newval |= value >> 2;
case BFD_RELOC_ARM_SBREL32:
case BFD_RELOC_ARM_PREL31:
case BFD_RELOC_ARM_TARGET2:
- case BFD_RELOC_ARM_TLS_LE32:
case BFD_RELOC_ARM_TLS_LDO32:
case BFD_RELOC_ARM_PCREL_CALL:
case BFD_RELOC_ARM_PCREL_JUMP:
case BFD_RELOC_ARM_TLS_GOTDESC:
case BFD_RELOC_ARM_TLS_GD32:
+ case BFD_RELOC_ARM_TLS_LE32:
case BFD_RELOC_ARM_TLS_IE32:
case BFD_RELOC_ARM_TLS_LDM32:
/* BFD will include the symbol's address in the addend.
-mthumb-interwork Code supports ARM/Thumb interworking
-m[no-]warn-deprecated Warn about deprecated features
+ -m[no-]warn-syms Warn when symbols match instructions
For now we will also provide support for:
{NULL, no_argument, NULL, 0}
};
+
size_t md_longopts_size = sizeof (md_longopts);
struct arm_option_table
{"mwarn-deprecated", NULL, &warn_on_deprecated, 1, NULL},
{"mno-warn-deprecated", N_("do not warn on use of deprecated feature"),
&warn_on_deprecated, 0, NULL},
+ {"mwarn-syms", N_("warn about symbols that match instruction names [default]"), (int *) (& flag_warn_syms), TRUE, NULL},
+ {"mno-warn-syms", N_("disable warnings about symobls that match instructions"), (int *) (& flag_warn_syms), FALSE, NULL},
{NULL, NULL, NULL, 0, NULL}
};
ARM_CPU_OPT ("mpcorenovfp", ARM_ARCH_V6K, FPU_NONE, "MPCore"),
ARM_CPU_OPT ("arm1156t2-s", ARM_ARCH_V6T2, FPU_NONE, NULL),
ARM_CPU_OPT ("arm1156t2f-s", ARM_ARCH_V6T2, FPU_ARCH_VFP_V2, NULL),
- ARM_CPU_OPT ("arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE, NULL),
- ARM_CPU_OPT ("arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2, NULL),
+ ARM_CPU_OPT ("arm1176jz-s", ARM_ARCH_V6KZ, FPU_NONE, NULL),
+ ARM_CPU_OPT ("arm1176jzf-s", ARM_ARCH_V6KZ, FPU_ARCH_VFP_V2, NULL),
ARM_CPU_OPT ("cortex-a5", ARM_ARCH_V7A_MP_SEC,
FPU_NONE, "Cortex-A5"),
ARM_CPU_OPT ("cortex-a7", ARM_ARCH_V7VE, FPU_ARCH_NEON_VFP_V4,
"Cortex-A15"),
ARM_CPU_OPT ("cortex-a17", ARM_ARCH_V7VE, FPU_ARCH_NEON_VFP_V4,
"Cortex-A17"),
+ ARM_CPU_OPT ("cortex-a35", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ "Cortex-A35"),
ARM_CPU_OPT ("cortex-a53", ARM_ARCH_V8A, 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 ("exynos-m1", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
"Samsung " \
"Exynos M1"),
+ ARM_CPU_OPT ("qdf24xx", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ "Qualcomm "
+ "QDF24XX"),
+
/* ??? XSCALE is really an architecture. */
ARM_CPU_OPT ("xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL),
/* ??? iwmmxt is not a processor. */
ARM_ARCH_OPT ("armv6j", ARM_ARCH_V6, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv6k", ARM_ARCH_V6K, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv6z", ARM_ARCH_V6Z, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv6zk", ARM_ARCH_V6ZK, FPU_ARCH_VFP),
+ /* The official spelling of this variant is ARMv6KZ, the name "armv6zk" is
+ kept to preserve existing behaviour. */
+ ARM_ARCH_OPT ("armv6kz", ARM_ARCH_V6KZ, FPU_ARCH_VFP),
+ ARM_ARCH_OPT ("armv6zk", ARM_ARCH_V6KZ, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv6t2", ARM_ARCH_V6T2, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv6zkt2", ARM_ARCH_V6ZKT2, FPU_ARCH_VFP),
+ /* The official spelling of this variant is ARMv6KZ, the name "armv6zkt2" is
+ kept to preserve existing behaviour. */
+ ARM_ARCH_OPT ("armv6kzt2", ARM_ARCH_V6KZT2, FPU_ARCH_VFP),
+ ARM_ARCH_OPT ("armv6zkt2", ARM_ARCH_V6KZT2, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv6-m", ARM_ARCH_V6M, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv6s-m", ARM_ARCH_V6SM, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv7", ARM_ARCH_V7, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv7-m", ARM_ARCH_V7M, FPU_ARCH_VFP),
ARM_ARCH_OPT ("armv7e-m", ARM_ARCH_V7EM, FPU_ARCH_VFP),
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 ("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),
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 ("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_EXT_DIV),
ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT),
ARM_FEATURE_CORE_LOW (ARM_EXT_V7A)),
+ ARM_EXT_OPT ("rdma", FPU_ARCH_NEON_VFP_ARMV8,
+ ARM_FEATURE_COPROC (FPU_NEON_ARMV8 | FPU_NEON_EXT_RDMA),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
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 }
{"neon-fp-armv8", FPU_ARCH_NEON_VFP_ARMV8},
{"crypto-neon-fp-armv8",
FPU_ARCH_CRYPTO_NEON_VFP_ARMV8},
+ {"neon-fp-armv8.1", FPU_ARCH_NEON_VFP_ARMV8_1},
+ {"crypto-neon-fp-armv8.1",
+ FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_1},
{NULL, ARM_ARCH_NONE}
};
mcpu_cpu_opt = &opt->value;
mcpu_fpu_opt = &opt->default_fpu;
if (opt->canonical_name)
- strcpy (selected_cpu_name, opt->canonical_name);
+ {
+ gas_assert (sizeof selected_cpu_name > strlen (opt->canonical_name));
+ strcpy (selected_cpu_name, opt->canonical_name);
+ }
else
{
size_t i;
+ if (len >= sizeof selected_cpu_name)
+ len = (sizeof selected_cpu_name) - 1;
+
for (i = 0; i < len; i++)
selected_cpu_name[i] = TOUPPER (opt->name[i]);
selected_cpu_name[i] = 0;