/* tc-arm.c -- Assemble for the ARM
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006
+ 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
Modified by David Taylor (dtaylor@armltd.co.uk)
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
static int support_interwork = FALSE;
static int uses_apcs_float = FALSE;
static int pic_code = FALSE;
+static int fix_v4bx = FALSE;
/* Variables that we set while parsing command-line options. Once all
options have been read we re-process these values to set the real
static const arm_feature_set arm_ext_v6z = ARM_FEATURE (ARM_EXT_V6Z, 0);
static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE (ARM_EXT_V6T2, 0);
static const arm_feature_set arm_ext_v6_notm = ARM_FEATURE (ARM_EXT_V6_NOTM, 0);
+static const arm_feature_set arm_ext_barrier = ARM_FEATURE (ARM_EXT_BARRIER, 0);
+static const arm_feature_set arm_ext_msr = ARM_FEATURE (ARM_EXT_THUMB_MSR, 0);
static const arm_feature_set arm_ext_div = ARM_FEATURE (ARM_EXT_DIV, 0);
static const arm_feature_set arm_ext_v7 = ARM_FEATURE (ARM_EXT_V7, 0);
static const arm_feature_set arm_ext_v7a = ARM_FEATURE (ARM_EXT_V7A, 0);
static const arm_feature_set arm_ext_v7r = ARM_FEATURE (ARM_EXT_V7R, 0);
-static const arm_feature_set arm_ext_v7m = ARM_FEATURE (ARM_EXT_V7M, 0);
+static const arm_feature_set arm_ext_m =
+ ARM_FEATURE (ARM_EXT_V6M | ARM_EXT_V7M, 0);
static const arm_feature_set arm_arch_any = ARM_ANY;
static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1);
static const arm_feature_set fpu_vfp_ext_v1 = ARM_FEATURE (0, FPU_VFP_EXT_V1);
static const arm_feature_set fpu_vfp_ext_v2 = ARM_FEATURE (0, FPU_VFP_EXT_V2);
static const arm_feature_set fpu_vfp_ext_v3 = ARM_FEATURE (0, FPU_VFP_EXT_V3);
+static const arm_feature_set fpu_vfp_ext_d32 =
+ ARM_FEATURE (0, FPU_VFP_EXT_D32);
static const arm_feature_set fpu_neon_ext_v1 = ARM_FEATURE (0, FPU_NEON_EXT_V1);
static const arm_feature_set fpu_vfp_v3_or_neon_ext =
ARM_FEATURE (0, FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3);
# endif
bfd_boolean
-arm_is_eabi(void)
+arm_is_eabi (void)
{
return (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4);
}
may differ from:
...
label:
- <insn>
-*/
+ <insn> */
symbolS * last_label_seen;
static int label_is_thumb_function_name = FALSE;
/* State variables for IT block handling. */
static bfd_boolean current_it_mask = 0;
static int current_cc;
-
\f
/* Pure syntax. */
case 'x':
case 'X':
- prec = 6;
+ prec = 5;
break;
case 'p':
case 'P':
- prec = 6;
+ prec = 5;
break;
default:
*sizeP = 0;
- return _("bad call to MD_ATOF()");
+ return _("Unrecognized or unsupported floating point constant");
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
- *sizeP = prec * 2;
+ *sizeP = prec * sizeof (LITTLENUM_TYPE);
if (target_big_endian)
{
for (i = 0; i < prec; i++)
{
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
+ md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
+ litP += sizeof (LITTLENUM_TYPE);
}
}
else
if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
for (i = prec - 1; i >= 0; i--)
{
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
+ md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
+ litP += sizeof (LITTLENUM_TYPE);
}
else
/* For a 4 byte float the order of elements in `words' is 1 0.
For an 8 byte float the order is 1 0 3 2. */
for (i = 0; i < prec; i += 2)
{
- md_number_to_chars (litP, (valueT) words[i + 1], 2);
- md_number_to_chars (litP + 2, (valueT) words[i], 2);
- litP += 4;
+ md_number_to_chars (litP, (valueT) words[i + 1],
+ sizeof (LITTLENUM_TYPE));
+ md_number_to_chars (litP + sizeof (LITTLENUM_TYPE),
+ (valueT) words[i], sizeof (LITTLENUM_TYPE));
+ litP += 2 * sizeof (LITTLENUM_TYPE);
}
}
- return 0;
+ return NULL;
}
/* We handle all bad expressions here, so that we can report the faulty
}
else
return FAIL;
-
+
*ccp = str;
-
+
return SUCCESS;
}
if (reg->neon)
atype = *reg->neon;
-
+
if (parse_neon_operand_type (&parsetype, &str) == SUCCESS)
{
if ((atype.defined & NTA_HASTYPE) != 0)
atype.defined |= NTA_HASTYPE;
atype.eltype = parsetype;
}
-
+
if (skip_past_char (&str, '[') == SUCCESS)
{
if (type != REG_TYPE_VFD)
first_error (_("only D registers may be indexed"));
return FAIL;
}
-
+
if ((atype.defined & NTA_HASINDEX) != 0)
{
first_error (_("can't change index for operand"));
atype.index = exp.X_add_number;
}
}
-
+
if (typeinfo)
*typeinfo = atype;
-
+
if (rtype)
*rtype = type;
-
+
*ccp = str;
-
+
return reg->number;
}
register (e.g. Neon double or quad reg when either has been requested).
- If this is a Neon vector type with additional type information, fill
in the struct pointed to by VECTYPE (if non-NULL).
- This function will fault on encountering a scalar.
-*/
+ This function will fault on encountering a scalar. */
static int
arm_typed_reg_parse (char **ccp, enum arm_reg_type type,
int reg;
char *str = *ccp;
struct neon_typed_alias atype;
-
+
reg = parse_typed_reg_or_scalar (&str, REG_TYPE_VFD, NULL, &atype);
-
+
if (reg == FAIL || (atype.defined & NTA_HASINDEX) == 0)
return FAIL;
-
+
if (atype.index == NEON_ALL_LANES)
{
first_error (_("scalar must have an index"));
first_error (_("scalar index out of range"));
return FAIL;
}
-
+
if (type)
*type = atype.eltype;
-
+
*ccp = str;
-
+
return reg * 16 + atype.index;
}
regtype = REG_TYPE_VFS;
max_regs = 32;
break;
-
+
case REGLIST_VFP_D:
regtype = REG_TYPE_VFD;
break;
-
+
case REGLIST_NEON_D:
regtype = REG_TYPE_NDQ;
break;
if (etype != REGLIST_VFP_S)
{
- /* VFPv3 allows 32 D registers. */
- if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
+ /* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant. */
+ if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
{
max_regs = 32;
if (thumb_mode)
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
- fpu_vfp_ext_v3);
+ fpu_vfp_ext_d32);
else
ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
- fpu_vfp_ext_v3);
+ fpu_vfp_ext_d32);
}
else
max_regs = 16;
first_error (_(reg_expected_msgs[regtype]));
return FAIL;
}
-
+
if (new_base >= max_regs)
{
first_error (_("register out of range in list"));
return FAIL;
}
-
+
/* Note: a value of 2 * n is returned for the register Q<n>. */
if (regtype == REG_TYPE_NQ)
{
{
if (!a && !b)
return 1;
-
+
if (!a || !b)
return 0;
if (a->defined != b->defined)
return 0;
-
+
if ((a->defined & NTA_HASTYPE) != 0
&& (a->eltype.type != b->eltype.type
|| a->eltype.size != b->eltype.size))
if ((a->defined & NTA_HASINDEX) != 0
&& (a->index != b->index))
return 0;
-
+
return 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 (skip_past_char (&ptr, '{') == SUCCESS)
leading_brace = 1;
-
+
do
{
struct neon_typed_alias atype;
first_error (_(reg_expected_msgs[rtype]));
return FAIL;
}
-
+
if (base_reg == -1)
{
base_reg = getreg;
first_error (_(type_error));
return FAIL;
}
-
+
/* Handle Dn-Dm or Qn-Qm syntax. Can only be used with non-indexed list
modes. */
if (ptr[0] == '-')
count += hireg + dregs - getreg;
continue;
}
-
+
/* If we're using Q registers, we can't use [] or [n] syntax. */
if (rtype == REG_TYPE_NQ)
{
count += 2;
continue;
}
-
+
if ((atype.defined & NTA_HASINDEX) != 0)
{
if (lane == -1)
count++;
}
while ((count != 1 || leading_brace) && skip_past_comma (&ptr) != FAIL);
-
+
/* No lane set by [x]. We must be interleaving structures. */
if (lane == -1)
lane = NEON_INTERLEAVE_LANES;
-
+
/* Sanity check. */
if (lane == -1 || base_reg == -1 || count < 1 || count > 4
|| (count > 1 && reg_incr == -1))
first_error (_("expected }"));
return FAIL;
}
-
+
if (reg_incr == -1)
reg_incr = 1;
*pbase = base_reg;
*str = ptr;
-
+
return lane | ((reg_incr - 1) << 4) | ((count - 1) << 5);
}
else if (new->number != number || new->type != type)
as_warn (_("ignoring redefinition of register alias '%s'"), str);
- return 0;
+ return NULL;
}
name = xstrdup (str);
if (hash_insert (arm_reg_hsh, name, (PTR) new))
abort ();
-
+
return new;
}
struct neon_typed_alias *atype)
{
struct reg_entry *reg = insert_reg_alias (str, number, type);
-
+
if (!reg)
{
first_error (_("attempt to redefine typed alias"));
return;
}
-
+
if (atype)
{
reg->neon = xmalloc (sizeof (struct neon_typed_alias));
new_register_name .req existing_register_name
If we find one, or if it looks sufficiently like one that we want to
- handle any error here, return non-zero. Otherwise return zero. */
+ handle any error here, return TRUE. Otherwise return FALSE. */
-static int
+static bfd_boolean
create_register_alias (char * newname, char *p)
{
struct reg_entry *old;
collapsed to single spaces. */
oldname = p;
if (strncmp (oldname, " .req ", 6) != 0)
- return 0;
+ return FALSE;
oldname += 6;
if (*oldname == '\0')
- return 0;
+ return FALSE;
old = hash_find (arm_reg_hsh, oldname);
if (!old)
{
as_warn (_("unknown register '%s' -- .req ignored"), oldname);
- return 1;
+ return TRUE;
}
/* If TC_CASE_SENSITIVE is defined, then newname already points to
/* Create aliases under the new name as stated; an all-lowercase
version of the new name; and an all-uppercase version of the new
name. */
- insert_reg_alias (nbuf, old->number, old->type);
-
- for (p = nbuf; *p; p++)
- *p = TOUPPER (*p);
+ if (insert_reg_alias (nbuf, old->number, old->type) != NULL)
+ {
+ for (p = nbuf; *p; p++)
+ *p = TOUPPER (*p);
- if (strncmp (nbuf, newname, nlen))
- insert_reg_alias (nbuf, old->number, old->type);
+ if (strncmp (nbuf, newname, nlen))
+ {
+ /* If this attempt to create an additional alias fails, do not bother
+ trying to create the all-lower case alias. We will fail and issue
+ a second, duplicate error message. This situation arises when the
+ programmer does something like:
+ foo .req r0
+ Foo .req r1
+ The second .req creates the "Foo" alias but then fails to create
+ the artificial FOO alias because it has already been created by the
+ first .req. */
+ if (insert_reg_alias (nbuf, old->number, old->type) == NULL)
+ return TRUE;
+ }
- for (p = nbuf; *p; p++)
- *p = TOLOWER (*p);
+ for (p = nbuf; *p; p++)
+ *p = TOLOWER (*p);
- if (strncmp (nbuf, newname, nlen))
- insert_reg_alias (nbuf, old->number, old->type);
+ if (strncmp (nbuf, newname, nlen))
+ insert_reg_alias (nbuf, old->number, old->type);
+ }
- return 1;
+ return TRUE;
}
/* Create a Neon typed/indexed register alias using directives, e.g.:
These typed registers can be used instead of the types specified after the
Neon mnemonic, so long as all operands given have types. Types can also be
specified directly, e.g.:
- vadd d0.s32, d1.s32, d2.s32
-*/
+ vadd d0.s32, d1.s32, d2.s32 */
static int
create_neon_reg_alias (char *newname, char *p)
struct neon_typed_alias typeinfo;
char *namebuf, *nameend;
int namelen;
-
+
typeinfo.defined = 0;
typeinfo.eltype.type = NT_invtype;
typeinfo.eltype.size = -1;
typeinfo.index = -1;
-
+
nameend = p;
-
+
if (strncmp (p, " .dn ", 5) == 0)
basetype = REG_TYPE_VFD;
else if (strncmp (p, " .qn ", 5) == 0)
basetype = REG_TYPE_NQ;
else
return 0;
-
+
p += 5;
-
+
if (*p == '\0')
return 0;
-
+
basereg = arm_reg_parse_multi (&p);
if (basereg && basereg->type != basetype)
as_bad (_("can't redefine the type of a register alias"));
return 0;
}
-
+
typeinfo.defined |= NTA_HASTYPE;
if (ntype.elems != 1)
{
}
typeinfo.eltype = ntype.el[0];
}
-
+
if (skip_past_char (&p, '[') == SUCCESS)
{
expressionS exp;
/* We got a scalar index. */
-
+
if (typeinfo.defined & NTA_HASINDEX)
{
as_bad (_("can't redefine the index of a scalar alias"));
return 0;
}
-
+
my_get_expression (&exp, &p, GE_NO_PREFIX);
-
+
if (exp.X_op != O_constant)
{
as_bad (_("scalar index must be constant"));
return 0;
}
-
+
typeinfo.defined |= NTA_HASINDEX;
typeinfo.index = exp.X_add_number;
-
+
if (skip_past_char (&p, ']') == FAIL)
{
as_bad (_("expecting ]"));
namebuf = alloca (namelen + 1);
strncpy (namebuf, newname, namelen);
namebuf[namelen] = '\0';
-
+
insert_neon_reg_alias (namebuf, basereg->number, basetype,
typeinfo.defined != 0 ? &typeinfo : NULL);
-
+
/* Insert name in all uppercase. */
for (p = namebuf; *p; p++)
*p = TOUPPER (*p);
-
+
if (strncmp (namebuf, newname, namelen))
insert_neon_reg_alias (namebuf, basereg->number, basetype,
typeinfo.defined != 0 ? &typeinfo : NULL);
-
+
/* Insert name in all lowercase. */
for (p = namebuf; *p; p++)
*p = TOLOWER (*p);
-
+
if (strncmp (namebuf, newname, namelen))
insert_neon_reg_alias (namebuf, basereg->number, basetype,
typeinfo.defined != 0 ? &typeinfo : NULL);
-
+
return 1;
}
name);
else
{
+ char * p;
+ char * nbuf;
+
hash_delete (arm_reg_hsh, name);
free ((char *) reg->name);
if (reg->neon)
free (reg->neon);
free (reg);
+
+ /* Also locate the all upper case and all lower case versions.
+ Do not complain if we cannot find one or the other as it
+ was probably deleted above. */
+
+ nbuf = strdup (name);
+ for (p = nbuf; *p; p++)
+ *p = TOUPPER (*p);
+ reg = hash_find (arm_reg_hsh, nbuf);
+ if (reg)
+ {
+ hash_delete (arm_reg_hsh, nbuf);
+ free ((char *) reg->name);
+ if (reg->neon)
+ free (reg->neon);
+ free (reg);
+ }
+
+ for (p = nbuf; *p; p++)
+ *p = TOLOWER (*p);
+ reg = hash_find (arm_reg_hsh, nbuf);
+ if (reg)
+ {
+ hash_delete (arm_reg_hsh, nbuf);
+ free ((char *) reg->name);
+ if (reg->neon)
+ free (reg->neon);
+ free (reg);
+ }
+
+ free (nbuf);
}
}
if (new_target == NULL)
{
- as_warn ("Failed to find real start of function: %s\n", name);
+ as_warn (_("Failed to find real start of function: %s\n"), name);
new_target = symbolP;
}
}
/* Add the literal in the global 'inst'
- structure to the relevent literal pool. */
+ structure to the relevant literal pool. */
static int
add_to_lit_pool (void)
{
demand_empty_rest_of_line ();
if (unwind.table_entry)
- as_bad (_("dupicate .handlerdata directive"));
+ as_bad (_("duplicate .handlerdata directive"));
create_unwind_entry (1);
}
if (unwind.personality_index >= 0 && unwind.personality_index < 3
&& !(marked_pr_dependency & (1 << unwind.personality_index)))
{
- static const char *const name[] = {
- "__aeabi_unwind_cpp_pr0",
- "__aeabi_unwind_cpp_pr1",
- "__aeabi_unwind_cpp_pr2"
- };
+ static const char *const name[] =
+ {
+ "__aeabi_unwind_cpp_pr0",
+ "__aeabi_unwind_cpp_pr1",
+ "__aeabi_unwind_cpp_pr2"
+ };
symbolS *pr = symbol_find_or_make (name[unwind.personality_index]);
fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE);
marked_pr_dependency |= 1 << unwind.personality_index;
|| !(mask & (1 << reg)))
{
/* We found an unsaved reg. Generate opcodes to save the
- preceeding block. */
+ preceding block. */
if (reg != hi_reg)
{
if (reg == 9)
ignore_rest_of_line ();
return;
}
+ input_line_pointer = peek;
s_arm_unwind_save_fpa (reg->number);
return;
#ifdef TE_PE
static void
-pe_directive_secrel (int dummy ATTRIBUTE_UNUSED)
+pe_directive_secrel (int dummy ATTRIBUTE_UNUSED)
{
expressionS exp;
}
else
return FAIL;
-
+
*str = ptr;
return SUCCESS;
char *fpnum;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
int found_fpchar = 0;
-
+
skip_past_char (&str, '#');
-
+
/* We must not accidentally parse an integer as a floating-point number. Make
sure that the value we parse is not an integer by checking for special
characters '.' or 'e'.
if (!found_fpchar)
return FAIL;
}
-
+
if ((str = atof_ieee (str, 's', words)) != NULL)
{
unsigned fpword = 0;
int i;
-
+
/* Our FP word must be 32 bits (single-precision FP). */
for (i = 0; i < 32 / LITTLENUM_NUMBER_OF_BITS; i++)
{
fpword <<= LITTLENUM_NUMBER_OF_BITS;
fpword |= words[i];
}
-
+
if (is_quarter_float (fpword) || (fpword & 0x7fffffff) == 0)
*immed = fpword;
else
return FAIL;
*ccp = str;
-
+
return SUCCESS;
}
-
+
return FAIL;
}
{
int length = strlen (group_reloc_table[i].name);
- if (strncasecmp (group_reloc_table[i].name, *str, length) == 0 &&
- (*str)[length] == ':')
+ if (strncasecmp (group_reloc_table[i].name, *str, length) == 0
+ && (*str)[length] == ':')
{
*out = &group_reloc_table[i];
*str += (length + 1);
p--;
}
- if (group_relocations &&
- ((*p == '#' && *(p + 1) == ':') || *p == ':'))
-
+ if (group_relocations
+ && ((*p == '#' && *(p + 1) == ':') || *p == ':'))
{
struct group_reloc_table_entry *entry;
parse_half (char **str)
{
char * p;
-
+
p = *str;
skip_past_char (&p, '#');
- if (strncasecmp (p, ":lower16:", 9) == 0)
+ if (strncasecmp (p, ":lower16:", 9) == 0)
inst.reloc.type = BFD_RELOC_ARM_MOVW;
else if (strncasecmp (p, ":upper16:", 9) == 0)
inst.reloc.type = BFD_RELOC_ARM_MOVT;
if (inst.reloc.type != BFD_RELOC_UNUSED)
{
p += 9;
- skip_whitespace(p);
+ skip_whitespace (p);
}
if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
inst.error = _("',' expected");
return FAIL;
}
-
+
if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
{
inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
enum arm_reg_type rtype;
char *ptr = *str;
struct neon_type_el optype;
-
+
if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
{
/* Case 4: VMOV<c><q>.<size> <Dn[x]>, <Rd>. */
if (skip_past_comma (&ptr) == FAIL)
goto wanted_comma;
-
+
if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
goto wanted_arm;
-
+
inst.operands[i].reg = val;
inst.operands[i].isreg = 1;
inst.operands[i].present = 1;
/* Cases 0, 1, 2, 3, 5 (D only). */
if (skip_past_comma (&ptr) == FAIL)
goto wanted_comma;
-
+
inst.operands[i].reg = val;
inst.operands[i].isreg = 1;
inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
inst.operands[i].isvec = 1;
inst.operands[i].vectype = optype;
inst.operands[i].present = 1;
-
+
if (skip_past_comma (&ptr) == SUCCESS)
{
/* Case 15. */
inst.operands[i].reg = val;
inst.operands[i].isreg = 1;
inst.operands[i++].present = 1;
-
+
if (skip_past_comma (&ptr) == FAIL)
goto wanted_comma;
-
+
if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
goto wanted_arm;
-
+
inst.operands[i].reg = val;
inst.operands[i].isreg = 1;
inst.operands[i++].present = 1;
inst.operands[i].reg = val;
inst.operands[i].isreg = 1;
inst.operands[i++].present = 1;
-
+
if (skip_past_comma (&ptr) == FAIL)
goto wanted_comma;
-
+
if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
{
/* Case 6: VMOV<c><q>.<dt> <Rd>, <Dn[x]> */
inst.operands[i].reg = val;
inst.operands[i].isreg = 1;
inst.operands[i++].present = 1;
-
+
if (skip_past_comma (&ptr) == FAIL)
goto wanted_comma;
-
+
if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFSD, &rtype, &optype))
== FAIL)
{
inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
inst.operands[i].vectype = optype;
inst.operands[i].present = 1;
-
+
if (rtype == REG_TYPE_VFS)
{
/* Case 14. */
*str = ptr;
return SUCCESS;
- wanted_comma:
+ wanted_comma:
first_error (_("expected comma"));
return FAIL;
-
- wanted_arm:
+
+ wanted_arm:
first_error (_(reg_expected_msgs[REG_TYPE_RN]));
return FAIL;
}
break;
default:
- as_fatal ("unhandled operand code %d", upat[i]);
+ as_fatal (_("unhandled operand code %d"), upat[i]);
}
/* Various value-based sanity checks and shared operations. We
if (!backtrack_pos)
{
/* The parse routine should already have set inst.error, but set a
- defaut here just in case. */
+ default here just in case. */
if (!inst.error)
inst.error = _("syntax error");
return FAIL;
if ((pos == VFP_REG_Dd || pos == VFP_REG_Dn || pos == VFP_REG_Dm)
&& reg > 15)
{
- if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
+ if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
{
if (thumb_mode)
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
- fpu_vfp_ext_v3);
+ fpu_vfp_ext_d32);
else
ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
- fpu_vfp_ext_v3);
+ fpu_vfp_ext_d32);
}
else
{
case VFP_REG_Dd:
inst.instruction |= ((reg & 15) << 12) | ((reg >> 4) << 22);
break;
-
+
case VFP_REG_Dn:
inst.instruction |= ((reg & 15) << 16) | ((reg >> 4) << 7);
break;
-
+
case VFP_REG_Dm:
inst.instruction |= (reg & 15) | ((reg >> 4) << 5);
break;
return 0;
}
-/* Functions for instruction encoding, sorted by subarchitecture.
+/* Functions for instruction encoding, sorted by sub-architecture.
First some generics; their names are taken from the conventional
bit positions for register arguments in ARM format instructions. */
{
constraint ((inst.instruction & 0xf0) != 0x40
&& inst.operands[0].imm != 0xf,
- "bad barrier type");
+ _("bad barrier type"));
inst.instruction |= inst.operands[0].imm;
}
else
static void
do_bx (void)
{
+ bfd_boolean want_reloc;
+
if (inst.operands[0].reg == REG_PC)
as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
inst.instruction |= inst.operands[0].reg;
+ /* Output R_ARM_V4BX relocations if is an EABI object that looks like
+ it is for ARMv4t or earlier. */
+ want_reloc = !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5);
+ if (object_arch && !ARM_CPU_HAS_FEATURE (*object_arch, arm_ext_v5))
+ want_reloc = TRUE;
+
+#ifdef OBJ_ELF
+ if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
+#endif
+ want_reloc = FALSE;
+
+ if (want_reloc)
+ inst.reloc.type = BFD_RELOC_ARM_V4BX;
}
MAR{cond} acc0, <RdLo>, <RdHi> == MCRR{cond} p0, #0, <RdLo>, <RdHi>, c0
MRA{cond} acc0, <RdLo>, <RdHi> == MRRC{cond} p0, #0, <RdLo>, <RdHi>, c0
- Result unpredicatable if Rd or Rn is R15. */
+ Result unpredictable if Rd or Rn is R15. */
static void
do_co_reg2c (void)
if (!inst.operands[1].present)
inst.operands[1].reg = inst.operands[0].reg + 1;
-
+
if (inst.instruction & LOAD_BIT)
{
/* encode_arm_addr_mode_3 will diagnose overlap between the base
reject [Rn,...]. */
if (inst.operands[1].preind)
{
- constraint (inst.reloc.exp.X_op != O_constant ||
- inst.reloc.exp.X_add_number != 0,
+ constraint (inst.reloc.exp.X_op != O_constant
+ || inst.reloc.exp.X_add_number != 0,
_("this instruction requires a post-indexed address"));
inst.operands[1].preind = 0;
reject [Rn,...]. */
if (inst.operands[1].preind)
{
- constraint (inst.reloc.exp.X_op != O_constant ||
- inst.reloc.exp.X_add_number != 0,
+ constraint (inst.reloc.exp.X_op != O_constant
+ || inst.reloc.exp.X_add_number != 0,
_("this instruction requires a post-indexed address"));
inst.operands[1].preind = 0;
do_vfp_nsyn_opcode ("fmrx");
else
return FAIL;
-
+
return SUCCESS;
}
inst.instruction |= inst.operands[2].reg;
inst.instruction |= inst.operands[3].reg << 8;
- /* rdhi, rdlo and rm must all be different. */
- if (inst.operands[0].reg == inst.operands[1].reg
- || inst.operands[0].reg == inst.operands[2].reg
+ /* rdhi and rdlo must be different. */
+ if (inst.operands[0].reg == inst.operands[1].reg)
+ as_tsktsk (_("rdhi and rdlo must be different"));
+
+ /* rdhi, rdlo and rm must all be different before armv6. */
+ if ((inst.operands[0].reg == inst.operands[2].reg
|| inst.operands[1].reg == inst.operands[2].reg)
+ && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
as_tsktsk (_("rdhi, rdlo and rm must all be different"));
}
encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
vfp_conv (32);
}
-
\f
/* FPA instructions. Also in a logical order. */
encode_arm_cp_address (2, TRUE, TRUE, 0);
}
-
\f
/* iWMMXt instructions: strictly in alphabetical order. */
case 4:
case 5:
case 6:
- case 7:
+ case 7:
/* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16. */
inst.operands[2].imm = 16;
inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20);
return;
}
- if (inst.instruction == T_MNEM_add)
+ if (inst.instruction == T_MNEM_add && (Rd == Rs || Rd == Rn))
{
- if (Rd == Rs)
+ /* Thumb-1 cores (except v6-M) require at least one high
+ register in a narrow non flag setting add. */
+ if (Rd > 7 || Rn > 7
+ || ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6t2)
+ || ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_msr))
{
+ if (Rd == Rn)
+ {
+ Rn = Rs;
+ Rs = Rd;
+ }
inst.instruction = T_OPCODE_ADD_HI;
inst.instruction |= (Rd & 8) << 4;
inst.instruction |= (Rd & 7);
inst.instruction |= Rn << 3;
return;
}
- /* ... because addition is commutative! */
- else if (Rd == Rn)
- {
- inst.instruction = T_OPCODE_ADD_HI;
- inst.instruction |= (Rd & 8) << 4;
- inst.instruction |= (Rd & 7);
- inst.instruction |= Rs << 3;
- return;
- }
}
}
/* If we get here, it can't be done in 16 bits. */
{
constraint ((inst.instruction & 0xf0) != 0x40
&& inst.operands[0].imm != 0xf,
- "bad barrier type");
+ _("bad barrier type"));
inst.instruction |= inst.operands[0].imm;
}
else
if (load)
inst.instruction |= 0x00100000;
- mask = ffs(mask) - 1;
+ mask = ffs (mask) - 1;
mask <<= 12;
}
else if (writeback)
if (inst.instruction < 0xffff)
inst.instruction = THUMB_OP32 (inst.instruction);
- encode_thumb2_ldmstm(inst.operands[0].reg, inst.operands[1].imm,
- inst.operands[0].writeback);
+ encode_thumb2_ldmstm (inst.operands[0].reg, inst.operands[1].imm,
+ inst.operands[0].writeback);
}
}
else
if (inst.operands[1].immisreg)
{
inst.instruction = THUMB_OP16 (opcode);
- /* [Rn, Ri] */
+ /* [Rn, Rik] */
if (Rn <= 7 && inst.operands[1].imm <= 7)
goto op16;
}
inst.instruction = THUMB_OP16 (inst.instruction);
goto op16;
}
-
+
inst.instruction = THUMB_OP16 (inst.instruction);
if (!inst.operands[1].isreg)
if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
inst.instruction |= inst.operands[0].reg << 12;
inst.instruction |= inst.operands[1].reg << 8;
encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE);
-
}
static void
opcode = narrow ? T_OPCODE_ROR_R : THUMB_OP32 (T_MNEM_ror);
break;
default:
- abort();
+ abort ();
}
inst.instruction = opcode;
flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
if (flags == 0)
{
- constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_m),
_("selected processor does not support "
"requested special purpose register"));
}
constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
_("'CPSR' or 'SPSR' expected"));
}
-
+
inst.instruction |= inst.operands[0].reg << 8;
inst.instruction |= (flags & SPSR_BIT) >> 2;
inst.instruction |= inst.operands[1].imm & 0xff;
}
else
{
- constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_m),
_("selected processor does not support "
"requested special purpose register"));
flags |= PSR_f;
do_t_push_pop (void)
{
unsigned mask;
-
+
constraint (inst.operands[0].writeback,
_("push/pop do not support {reglist}^"));
constraint (inst.reloc.type != BFD_RELOC_UNUSED,
else if (unified_syntax)
{
inst.instruction = THUMB_OP32 (inst.instruction);
- encode_thumb2_ldmstm(13, mask, TRUE);
+ encode_thumb2_ldmstm (13, mask, TRUE);
}
else
{
case SHIFT_ROR: inst.instruction = T_OPCODE_ROR_R; break;
default: abort ();
}
-
+
inst.instruction |= inst.operands[0].reg;
inst.instruction |= inst.operands[2].reg << 3;
}
case T_MNEM_ror: inst.instruction = T_OPCODE_ROR_R; break;
default: abort ();
}
-
+
inst.instruction |= inst.operands[0].reg;
inst.instruction |= inst.operands[2].reg << 3;
}
}
/* Neon instruction encoder helpers. */
-
+
/* Encodings for the different types for various Neon opcodes. */
/* An "invalid" code for the following tables. */
unsigned float_or_poly;
unsigned scalar_or_imm;
};
-
+
/* Map overloaded Neon opcodes to their respective encodings. */
#define NEON_ENC_TAB \
X(vabd, 0x0000700, 0x1200d00, N_INV), \
S - Scalar
R - ARM register
L - D<n> register list
-
+
This table is used to generate various data:
- enumerations of the form NS_DDR to be used as arguments to
neon_select_shape.
- a table classifying shapes into single, double, quad, mixed.
- - a table used to drive neon_select_shape.
-*/
+ - a table used to drive neon_select_shape. */
#define NEON_SHAPE_DEF \
X(3, (D, D, D), DOUBLE), \
inst.operands[1] = inst.operands[0];
va_start (ap, shape);
-
+
for (; shape != NS_NULL; shape = va_arg (ap, int))
{
unsigned j;
if (matches)
break;
}
-
+
va_end (ap);
if (shape == NS_NULL && first_shape != NS_NULL)
*g_type = NT_untyped;
}
}
-
+
/* Return operand OPNO promoted by bits set in THISARG. KEY should be the "key"
operand type, i.e. the single type specified in a Neon instruction when it
is the only one given. */
neon_type_promote (struct neon_type_el *key, unsigned thisarg)
{
struct neon_type_el dest = *key;
-
+
assert ((thisarg & N_EQK) != 0);
-
+
neon_modify_type_size (thisarg, &dest.type, &dest.size);
return dest;
default: ;
}
-
+
return N_UTYP;
}
*type = NT_float;
else
return FAIL;
-
+
return SUCCESS;
}
enum neon_el_type type;
unsigned destmask;
int i;
-
+
destmask = 0;
-
+
for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
{
if (el_type_of_type_chk (&type, &size, allowed & i) == SUCCESS)
destmask |= type_chk_of_el_type (type, size);
}
}
-
+
return destmask;
}
return badtype;
}
}
-
+
if ((thisarg & N_EQK) == 0)
{
unsigned given_type = type_chk_of_el_type (g_type, g_size);
do_vfp_nsyn_opcode (const char *opname)
{
const struct asm_opcode *opcode;
-
+
opcode = hash_find (arm_ops_hsh, opname);
if (!opcode)
et = neon_check_type (2, rs,
N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
break;
-
+
case 3:
rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
et = neon_check_type (3, rs,
do_vfp_nsyn_mla_mls (enum neon_shape rs)
{
int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
-
+
if (rs == NS_FFF)
{
if (is_mla)
{
enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
-
+
if (rs == NS_FF)
do_vfp_nsyn_opcode ("fsqrts");
else
enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
N_F32 | N_F64 | N_KEY | N_VFP);
-
+
if (rs == NS_FFF)
do_vfp_nsyn_opcode ("fdivs");
else
enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
N_F32 | N_F64 | N_KEY | N_VFP);
-
+
if (rs == NS_FFF)
{
inst.instruction = NEON_ENC_SINGLE (inst.instruction);
{
enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
-
+
if (rs == NS_FF)
{
inst.instruction = NEON_ENC_SINGLE (inst.instruction);
default:
abort ();
}
-
+
if (rs == NS_FI)
{
inst.instruction = NEON_ENC_SINGLE (inst.instruction);
/* The U bit is at bit 24 by default. Move to bit 28 in Thumb mode. */
if (i & (1 << 24))
i |= 1 << 28;
-
+
i &= ~(1 << 24);
-
+
i |= 0xef000000;
}
else
i |= 0xf2000000;
-
+
return i;
}
|28/24|23|22 |21 20|19 16|15 12|11 8|7|6|5|4|3 0|
| U |x |D |size | Rn | Rd |x x x x|N|Q|M|x| Rm |
-
+
SIZE is passed in bits. -1 means size field isn't changed, in case it has a
different meaning for some instruction. */
inst.instruction |= (ubit != 0) << 24;
if (size != -1)
inst.instruction |= neon_logbits (size) << 20;
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
the instruction. *OP is passed as the initial value of the op field, and
may be set to a different value depending on the constant (i.e.
"MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not
- MVN). If the immediate looks like a repeated parttern then also
+ MVN). If the immediate looks like a repeated pattern then also
try smaller element sizes. */
static int
enum neon_opc opcode = inst.instruction & 0x0fffffff;
unsigned immbits;
int cmode;
-
+
if (et.type == NT_invtype)
return;
-
+
inst.instruction = NEON_ENC_IMMED (inst.instruction);
immbits = inst.operands[1].imm;
case N_MNEM_vbic:
cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
break;
-
+
case N_MNEM_vorr:
cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
break;
-
+
case N_MNEM_vand:
/* Pseudo-instruction for VBIC. */
neon_invert_size (&immbits, 0, et.size);
cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
break;
-
+
case N_MNEM_vorn:
/* Pseudo-instruction for VORR. */
neon_invert_size (&immbits, 0, et.size);
cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
break;
-
+
default:
abort ();
}
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
inst.instruction |= cmode << 8;
neon_write_immbits (immbits);
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
}
if (inst.uncond_value != -1)
inst.instruction |= inst.uncond_value << 28;
}
-
+
if ((check & NEON_CHECK_ARCH)
&& !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
{
first_error (_(BAD_FPU));
return FAIL;
}
-
+
return SUCCESS;
}
inst.instruction |= neon_quad (rs) << 6;
inst.instruction |= (et.type == NT_float) << 10;
inst.instruction |= neon_logbits (et.size) << 18;
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
}
if (regno > 7 || elno > 3)
goto bad_scalar;
return regno | (elno << 3);
-
+
case 32:
if (regno > 15 || elno > 1)
goto bad_scalar;
/* Give a more helpful error message if we have an invalid type. */
if (et.type == NT_invtype)
return;
-
+
scalar = neon_scalar_for_mul (inst.operands[2].reg, et.size);
inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
{
enum neon_shape rs;
struct neon_type_el et;
-
+
if (try_vfp_nsyn (2, do_vfp_nsyn_abs_neg) == SUCCESS)
return;
rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_F32 | N_KEY);
-
+
inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
inst.instruction |= LOW4 (inst.operands[1].reg);
inst.instruction |= neon_quad (rs) << 6;
inst.instruction |= (et.type == NT_float) << 10;
inst.instruction |= neon_logbits (et.size) << 18;
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
/* This gets the bounds check, size encoding and immediate bits calculation
right. */
et.size /= 2;
-
+
/* VQ{R}SHRN.I<size> <Dd>, <Qm>, #0 is a synonym for
VQMOVN.I<size> <Dd>, <Qm>. */
if (imm == 0)
do_neon_qmovn ();
return;
}
-
+
constraint (imm < 1 || (unsigned)imm > et.size,
_("immediate out of range"));
neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, et.size - imm);
/* This gets the bounds check, size encoding and immediate bits calculation
right. */
et.size /= 2;
-
+
/* If immediate is zero then we are a pseudo-instruction for
VMOVN.I<size> <Dd>, <Qm> */
if (imm == 0)
do_neon_movn ();
return;
}
-
+
constraint (imm < 1 || (unsigned)imm > et.size,
_("immediate out of range for narrowing operation"));
neon_imm_shift (FALSE, 0, 0, et, et.size - imm);
inst.instruction |= LOW4 (inst.operands[1].reg);
inst.instruction |= HI1 (inst.operands[1].reg) << 5;
inst.instruction |= neon_logbits (et.size) << 18;
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
else
"source" and "destination" registers must have the same width. Hack that
here by making the size equal to the key (wider, in this case) operand. */
unsigned key = (rs == NS_QQI || rs == NS_DDI || rs == NS_FFI) ? N_KEY : 0;
-
+
CVT_VAR (0, N_S32, N_F32);
CVT_VAR (1, N_U32, N_F32);
CVT_VAR (2, N_F32, N_S32);
CVT_VAR (3, N_F32, N_U32);
-
+
whole_reg = N_VFP;
-
+
/* VFP instructions. */
CVT_VAR (4, N_F32, N_F64);
CVT_VAR (5, N_F64, N_F32);
CVT_VAR (15, N_U16, N_F32 | key);
CVT_VAR (16, N_S16, N_F64 | key);
CVT_VAR (17, N_U16, N_F64 | key);
-
+
return -1;
#undef CVT_VAR
}
do_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
{
const char *opname = 0;
-
+
if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI)
{
/* Conversions with immediate bitshift. */
if (inst.operands[1].isreg)
{
enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-
+
inst.instruction = NEON_ENC_INTEGER (inst.instruction);
inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
/* Encode instructions of form:
|28/24|23|22|21 20|19 16|15 12|11 8|7|6|5|4|3 0|
- | U |x |D |size | Rn | Rd |x x x x|N|x|M|x| Rm |
-
-*/
+ | U |x |D |size | Rn | Rd |x x x x|N|x|M|x| Rm | */
static void
neon_mixed_length (struct neon_type_el et, unsigned size)
inst.instruction |= HI1 (inst.operands[2].reg) << 5;
inst.instruction |= (et.type == NT_unsigned) << 24;
inst.instruction |= neon_logbits (size) << 20;
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
inst.instruction |= HI1 (inst.operands[2].reg) << 5;
inst.instruction |= neon_quad (rs) << 6;
inst.instruction |= imm << 8;
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
inst.instruction |= neon_quad (rs) << 6;
inst.instruction |= x << 17;
inst.instruction |= sizebits << 16;
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
else
(Two ARM regs to two VFP singles.)
15. VMOV <Sd>, <Se>, <Rn>, <Rm>
(Two VFP singles to two ARM regs.)
-
+
These cases can be disambiguated using neon_select_shape, except cases 1/9
and 3/11 which depend on the operand type too.
-
+
All the encoded bits are hardcoded by this function.
-
+
Cases 4, 6 may be used with VFPv1 and above (only 32-bit transfers!).
Cases 5, 7 may be used with VFPv2 and above.
-
+
FIXME: Some of the checking may be a bit sloppy (in a couple of cases you
- can specify a type where it doesn't make sense to, and is ignored).
-*/
+ can specify a type where it doesn't make sense to, and is ignored). */
static void
do_neon_mov (void)
inst.instruction = neon_dp_fixup (inst.instruction);
}
break;
-
+
case NS_DI: /* case 3/11. */
et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
inst.error = NULL;
neon_move_immediate ();
inst.instruction = neon_dp_fixup (inst.instruction);
break;
-
+
case NS_SR: /* case 4. */
{
unsigned bcdebits = 0;
inst.instruction |= (bcdebits >> 2) << 21;
}
break;
-
+
case NS_DRR: /* case 5 (fmdrr). */
constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
_(BAD_FPU));
inst.instruction |= inst.operands[1].reg << 12;
inst.instruction |= inst.operands[2].reg << 16;
break;
-
+
case NS_RS: /* case 6. */
{
struct neon_type_el et = neon_check_type (2, NS_NULL,
inst.instruction |= (abcdebits >> 2) << 21;
}
break;
-
+
case NS_RRD: /* case 7 (fmrrd). */
constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
_(BAD_FPU));
inst.instruction |= LOW4 (inst.operands[2].reg);
inst.instruction |= HI1 (inst.operands[2].reg) << 5;
break;
-
+
case NS_FF: /* case 8 (fcpys). */
do_vfp_nsyn_opcode ("fcpys");
break;
-
+
case NS_FI: /* case 10 (fconsts). */
ldconst = "fconsts";
encode_fconstd:
else
first_error (_("immediate out of range"));
break;
-
+
case NS_RF: /* case 12 (fmrs). */
do_vfp_nsyn_opcode ("fmrs");
break;
-
+
case NS_FR: /* case 13 (fmsr). */
do_vfp_nsyn_opcode ("fmsr");
break;
-
+
/* The encoders for the fmrrs and fmsrr instructions expect three operands
(one of which is a list), but we have parsed four. Do some fiddling to
make the operands what do_vfp_reg2_from_sp2 and do_vfp_sp2_from_reg2
memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
do_vfp_nsyn_opcode ("fmrrs");
break;
-
+
case NS_FFRR: /* case 15 (fmsrr). */
constraint (inst.operands[1].reg != inst.operands[0].reg + 1,
_("VFP registers must be adjacent"));
memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
do_vfp_nsyn_opcode ("fmsrr");
break;
-
+
default:
abort ();
}
{
unsigned listlenbits;
neon_check_type (3, NS_DLD, N_EQK, N_EQK, N_8 | N_KEY);
-
+
if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
{
first_error (_("bad list length for table lookup"));
return;
}
-
+
listlenbits = inst.operands[1].imm - 1;
inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
inst.instruction |= LOW4 (inst.operands[2].reg);
inst.instruction |= HI1 (inst.operands[2].reg) << 5;
inst.instruction |= listlenbits << 8;
-
+
inst.instruction = neon_dp_fixup (inst.instruction);
}
inst.instruction |= HI1 (inst.operands[1].reg) << 22;
inst.instruction |= offsetbits;
-
+
do_vfp_cond_or_thumb ();
}
do_neon_ldr_str (void)
{
int is_ldr = (inst.instruction & (1 << 20)) != 0;
-
+
if (inst.operands[0].issingle)
{
if (is_ldr)
| (((inst.instruction >> 8) & 3) << 3);
typebits = typetable[idx];
-
+
constraint (typebits == -1, _("bad list type for instruction"));
inst.instruction &= ~0xf00;
{
va_list ap;
int result = FAIL, thissize, thisalign;
-
+
if (!inst.operands[1].immisalign)
{
*do_align = 0;
return SUCCESS;
}
-
+
va_start (ap, do_align);
do
*do_align = 1;
else
first_error (_("unsupported alignment for instruction"));
-
+
return result;
}
int align = inst.operands[1].imm >> 8;
int n = (inst.instruction >> 8) & 3;
int max_el = 64 / et.size;
-
+
if (et.type == NT_invtype)
return;
-
+
constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != n + 1,
_("bad list length"));
constraint (NEON_LANE (inst.operands[0].imm) >= max_el,
constraint (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2
&& et.size == 8,
_("stride of 2 unavailable when element size is 8"));
-
+
switch (n)
{
case 0: /* VLD1 / VST1. */
/* Reg stride of 2 is encoded in bit 5 when size==16, bit 6 when size==32. */
if (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2)
inst.instruction |= 1 << (4 + logsize);
-
+
inst.instruction |= NEON_LANE (inst.operands[0].imm) << (logsize + 5);
inst.instruction |= logsize << 10;
}
inst.instruction = NEON_ENC_INTERLV (inst.instruction);
do_neon_ld_st_interleave ();
break;
-
+
case NEON_ALL_LANES:
inst.instruction = NEON_ENC_DUP (inst.instruction);
do_neon_ld_dup ();
break;
-
+
default:
inst.instruction = NEON_ENC_LANE (inst.instruction);
do_neon_ld_st_lane ();
inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
inst.instruction |= inst.operands[1].reg << 16;
-
+
if (inst.operands[1].postind)
{
int postreg = inst.operands[1].imm & 0xf;
inst.instruction |= 0xd;
}
else
- inst.instruction |= 0xf;
-
+ inst.instruction |= 0xf;
+
if (thumb_mode)
inst.instruction |= 0xf9000000;
else
inst.instruction |= 0xf4000000;
}
-
\f
/* Overall per-instruction processing. */
as_bad ("%s -- `%s'", inst.error, str);
return;
}
- if (inst.relax) {
- output_relax_insn();
+ if (inst.relax)
+ {
+ output_relax_insn ();
return;
- }
+ }
if (inst.size == 0)
return;
const struct asm_cond *cond;
char save[2];
bfd_boolean neon_supported;
-
+
neon_supported = ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1);
/* Scan up to the end of the mnemonic, which must end in white space,
if (end[0] == '.')
{
int offset = 2;
-
+
/* The .w and .n suffixes are only valid if the unified syntax is in
use. */
if (unified_syntax && end[1] == 'w')
*str = end + offset;
- if (end[offset] == '.')
+ if (end[offset] == '.')
{
/* See if we have a Neon type suffix (possible in either unified or
non-unified ARM syntax mode). */
{
/* Implicit require narrow instructions on Thumb-1. This avoids
relaxation accidentally introducing Thumb-2 instructions. */
- if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23)
+ if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23
+ && !ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_msr))
inst.size_req = 2;
}
}
else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
{
- as_bad (_("thumb conditional instrunction not in IT block"));
+ as_bad (_("thumb conditional instruction not in IT block"));
return;
}
*opcode->tvariant);
/* 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.
+ 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)
+ if (((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
+ || inst.relax)
+ && !ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_msr))
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
arm_ext_v6t2);
}
else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
{
+ bfd_boolean is_bx;
+
+ /* bx is allowed on v5 cores, and sometimes on v4 cores. */
+ is_bx = (opcode->aencode == do_bx);
+
/* Check that this instruction is supported for this CPU. */
- if (!opcode->avariant ||
- !ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
+ if (!(is_bx && fix_v4bx)
+ && !(opcode->avariant &&
+ ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant)))
{
as_bad (_("selected processor does not support `%s'"), str);
return;
opcode->aencode ();
/* Arm mode bx is marked as both v4T and v5 because it's still required
on a hypothetical non-thumb v5 core. */
- if (ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v4t)
- || ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v5))
+ if (is_bx)
ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, arm_ext_v4t);
else
ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
ARM_SET_INTERWORK (sym, support_interwork);
#endif
- /* Note - do not allow local symbols (.Lxxx) to be labeled
+ /* Note - do not allow local symbols (.Lxxx) to be labelled
as Thumb functions. This is because these labels, whilst
they exist inside Thumb code, are not the entry points for
possible ARM->Thumb calls. Also, these labels can be used
#undef ARM_VARIANT
#define ARM_VARIANT &arm_ext_v3 /* ARM 6 Status register instructions. */
+#undef THUMB_VARIANT
+#define THUMB_VARIANT &arm_ext_msr
TCE(mrs, 10f0000, f3ef8000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
TCE(msr, 120f000, f3808000, 2, (RVC_PSR, RR_EXi), msr, t_msr),
#undef ARM_VARIANT
#define ARM_VARIANT &arm_ext_v3m /* ARM 7M long multiplies. */
+#undef THUMB_VARIANT
+#define THUMB_VARIANT &arm_ext_v6t2
TCE(smull, 0c00090, fb800000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
CM(smull,s, 0d00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
TCE(umull, 0800090, fba00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
TCE(sdiv, 0, fb90f0f0, 3, (RR, oRR, RR), 0, t_div),
TCE(udiv, 0, fbb0f0f0, 3, (RR, oRR, RR), 0, t_div),
+ /* ARM V6M/V7 instructions. */
+#undef ARM_VARIANT
+#define ARM_VARIANT &arm_ext_barrier
+#undef THUMB_VARIANT
+#define THUMB_VARIANT &arm_ext_barrier
+ TUF(dmb, 57ff050, f3bf8f50, 1, (oBARRIER), barrier, t_barrier),
+ TUF(dsb, 57ff040, f3bf8f40, 1, (oBARRIER), barrier, t_barrier),
+ TUF(isb, 57ff060, f3bf8f60, 1, (oBARRIER), barrier, t_barrier),
+
/* ARM V7 instructions. */
#undef ARM_VARIANT
#define ARM_VARIANT &arm_ext_v7
#define THUMB_VARIANT &arm_ext_v7
TUF(pli, 450f000, f910f000, 1, (ADDR), pli, t_pld),
TCE(dbg, 320f0f0, f3af80f0, 1, (I15), dbg, t_dbg),
- TUF(dmb, 57ff050, f3bf8f50, 1, (oBARRIER), barrier, t_barrier),
- TUF(dsb, 57ff040, f3bf8f40, 1, (oBARRIER), barrier, t_barrier),
- TUF(isb, 57ff060, f3bf8f60, 1, (oBARRIER), barrier, t_barrier),
#undef ARM_VARIANT
#define ARM_VARIANT &fpu_fpa_ext_v1 /* Core FPA instruction set (V1). */
buf = fragp->fr_literal + fragp->fr_fix;
old_op = bfd_get_16(abfd, buf);
- if (fragp->fr_symbol) {
+ if (fragp->fr_symbol)
+ {
exp.X_op = O_symbol;
exp.X_add_symbol = fragp->fr_symbol;
- } else {
+ }
+ else
+ {
exp.X_op = O_constant;
- }
+ }
exp.X_add_number = fragp->fr_offset;
opcode = fragp->fr_subtype;
switch (opcode)
case T_MNEM_strh:
if (fragp->fr_var == 4)
{
- insn = THUMB_OP32(opcode);
+ insn = THUMB_OP32 (opcode);
if ((old_op >> 12) == 4 || (old_op >> 12) == 9)
{
insn |= (old_op & 0x700) << 4;
pc_rel = 0;
break;
default:
- abort();
+ abort ();
}
fixp = fix_new_exp (fragp, fragp->fr_fix, fragp->fr_var, &exp, pc_rel,
reloc_type);
/* Get the address of a symbol during relaxation. */
static addressT
-relaxed_symbol_addr(fragS *fragp, long stretch)
+relaxed_symbol_addr (fragS *fragp, long stretch)
{
fragS *sym_frag;
addressT addr;
if (stretch != 0
&& sym_frag->relax_marker != fragp->relax_marker)
- addr += stretch;
+ {
+ fragS *f;
+
+ /* Adjust stretch for any alignment frag. Note that if have
+ been expanding the earlier code, the symbol may be
+ defined in what appears to be an earlier frag. FIXME:
+ This doesn't handle the fr_subtype field, which specifies
+ a maximum number of bytes to skip when doing an
+ alignment. */
+ for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
+ {
+ if (f->fr_type == rs_align || f->fr_type == rs_align_code)
+ {
+ if (stretch < 0)
+ stretch = - ((- stretch)
+ & ~ ((1 << (int) f->fr_offset) - 1));
+ else
+ stretch &= ~ ((1 << (int) f->fr_offset) - 1);
+ if (stretch == 0)
+ break;
+ }
+ }
+ if (f != NULL)
+ addr += stretch;
+ }
return addr;
}
offsetT val;
/* Assume worst case for symbols not known to be in the same section. */
- if (!S_IS_DEFINED(fragp->fr_symbol)
+ if (!S_IS_DEFINED (fragp->fr_symbol)
|| sec != S_GET_SEGMENT (fragp->fr_symbol))
return 4;
- val = relaxed_symbol_addr(fragp, stretch);
+ val = relaxed_symbol_addr (fragp, stretch);
addr = fragp->fr_address + fragp->fr_fix;
addr = (addr + 4) & ~3;
/* Force misaligned targets to 32-bit variant. */
offsetT limit;
/* Assume worst case for symbols not known to be in the same section. */
- if (!S_IS_DEFINED(fragp->fr_symbol)
+ if (!S_IS_DEFINED (fragp->fr_symbol)
|| sec != S_GET_SEGMENT (fragp->fr_symbol))
return 4;
- val = relaxed_symbol_addr(fragp, stretch);
+ val = relaxed_symbol_addr (fragp, stretch);
addr = fragp->fr_address + fragp->fr_fix + 4;
val -= addr;
switch (fragp->fr_subtype)
{
case T_MNEM_ldr_pc2:
- newsize = relax_adr(fragp, sec, stretch);
+ newsize = relax_adr (fragp, sec, stretch);
break;
case T_MNEM_ldr_pc:
case T_MNEM_ldr_sp:
case T_MNEM_str_sp:
- newsize = relax_immediate(fragp, 8, 2);
+ newsize = relax_immediate (fragp, 8, 2);
break;
case T_MNEM_ldr:
case T_MNEM_str:
- newsize = relax_immediate(fragp, 5, 2);
+ newsize = relax_immediate (fragp, 5, 2);
break;
case T_MNEM_ldrh:
case T_MNEM_strh:
- newsize = relax_immediate(fragp, 5, 1);
+ newsize = relax_immediate (fragp, 5, 1);
break;
case T_MNEM_ldrb:
case T_MNEM_strb:
- newsize = relax_immediate(fragp, 5, 0);
+ newsize = relax_immediate (fragp, 5, 0);
break;
case T_MNEM_adr:
- newsize = relax_adr(fragp, sec, stretch);
+ newsize = relax_adr (fragp, sec, stretch);
break;
case T_MNEM_mov:
case T_MNEM_movs:
case T_MNEM_cmp:
case T_MNEM_cmn:
- newsize = relax_immediate(fragp, 8, 0);
+ newsize = relax_immediate (fragp, 8, 0);
break;
case T_MNEM_b:
- newsize = relax_branch(fragp, sec, 11, stretch);
+ newsize = relax_branch (fragp, sec, 11, stretch);
break;
case T_MNEM_bcond:
- newsize = relax_branch(fragp, sec, 8, stretch);
+ newsize = relax_branch (fragp, sec, 8, stretch);
break;
case T_MNEM_add_sp:
case T_MNEM_add_pc:
newsize = relax_addsub (fragp, sec);
break;
default:
- abort();
+ abort ();
}
fragp->fr_var = newsize;
/* Freeze wide instructions that are at or before the same location as
in the previous pass. This avoids infinite loops.
- Don't freeze them unconditionally because targets may be artificialy
- misaligned by the expansion of preceeding frags. */
+ Don't freeze them unconditionally because targets may be artificially
+ misaligned by the expansion of preceding frags. */
if (stretch <= 0 && newsize > 2)
{
md_convert_frag (sec->owner, sec, fragp);
- frag_wane(fragp);
+ frag_wane (fragp);
}
return newsize - oldsize;
static void add_unwind_adjustsp (offsetT);
-/* Cenerate and deferred unwind frame offset. */
+/* Generate any deferred unwind frame offset. */
static void
flush_pending_unwind (void)
group_name = elf_group_name (text_seg);
if (group_name == NULL)
{
- as_bad ("Group section `%s' has no group signature",
+ as_bad (_("Group section `%s' has no group signature"),
segment_name (text_seg));
ignore_rest_of_line ();
return;
obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0);
- /* Set the setion link for index tables. */
+ /* Set the section link for index tables. */
if (idx)
elf_linked_to_section (now_seg) = text_seg;
}
if (unwind.personality_index == -2)
{
if (have_data)
- as_bad (_("handerdata in cantunwind frame"));
+ as_bad (_("handlerdata in cantunwind frame"));
return 1; /* EXIDX_CANTUNWIND. */
}
will need. Otherwise we want to use the calculated base.
For WinCE we skip the bias for externals as well, since this
is how the MS ARM-CE assembler behaves and we want to be compatible. */
- if (fixP->fx_pcrel
+ if (fixP->fx_pcrel
&& ((fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != seg)
|| (arm_force_relocation (fixP)
#ifdef TE_WINCE
case BFD_RELOC_ARM_PCREL_BLX:
case BFD_RELOC_ARM_PLT32:
#ifdef TE_WINCE
- /* When handling fixups immediately, because we have already
+ /* When handling fixups immediately, because we have already
discovered the value of a symbol, or the address of the frag involved
we must account for the offset by +8, as the OS loader will never see the reloc.
see fixup_segment() in write.c
if (!GOT_symbol)
{
if (symbol_find (name))
- as_bad ("GOT already in the symbol table");
+ as_bad (_("GOT already in the symbol table"));
GOT_symbol = symbol_new (name, undefined_section,
(valueT) 0, & zero_address_frag);
fixP->fx_done = 1;
/* On a 64-bit host, silently truncate 'value' to 32 bits for
- consistency with the behavior on 32-bit hosts. Remember value
+ consistency with the behaviour on 32-bit hosts. Remember value
for emit_reloc. */
value &= 0xffffffff;
value ^= 0x80000000;
- value -= 0x80000000;
+ value -= 0x80000000;
*valP = value;
fixP->fx_addnumber = value;
newval = md_chars_to_number (buf, THUMB_SIZE);
if (value < 0 || value > 255)
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("invalid immediate: %ld is too large"),
+ _("invalid immediate: %ld is out of range"),
(long) value);
newval |= value;
md_number_to_chars (buf, newval, THUMB_SIZE);
/* REL format relocations are limited to a 16-bit addend. */
if (!fixP->fx_done)
{
- if (value < -0x1000 || value > 0xffff)
+ if (value < -0x8000 || value > 0x7fff)
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("offset too big"));
+ _("offset out of range"));
}
else if (fixP->fx_r_type == BFD_RELOC_ARM_MOVT
|| fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
if (encoded_addend == (unsigned int) FAIL)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("the offset 0x%08lX is not representable"),
- addend_abs);
+ (unsigned long) addend_abs);
/* Extract the instruction. */
insn = md_chars_to_number (buf, INSN_SIZE);
instruction. */
insn &= 0xfffff000;
insn |= encoded_addend;
-
- /* Update the instruction. */
+
+ /* Update the instruction. */
md_number_to_chars (buf, insn, INSN_SIZE);
}
break;
if (addend_abs >= 0x1000)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("bad offset 0x%08lX (only 12 bits available for the magnitude)"),
- addend_abs);
+ (unsigned long) addend_abs);
/* Extract the instruction. */
insn = md_chars_to_number (buf, INSN_SIZE);
of the instruction. */
insn &= 0xfffff000;
insn |= addend_abs;
-
- /* Update the instruction. */
+
+ /* Update the instruction. */
md_number_to_chars (buf, insn, INSN_SIZE);
}
break;
if (addend_abs >= 0x100)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("bad offset 0x%08lX (only 8 bits available for the magnitude)"),
- addend_abs);
+ (unsigned long) addend_abs);
/* Extract the instruction. */
insn = md_chars_to_number (buf, INSN_SIZE);
four into bits 8 .. 11. */
insn &= 0xfffff0f0;
insn |= (addend_abs & 0xf) | ((addend_abs & 0xf0) << 4);
-
- /* Update the instruction. */
+
+ /* Update the instruction. */
md_number_to_chars (buf, insn, INSN_SIZE);
}
break;
if (addend_abs & 0x3)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("bad offset 0x%08lX (must be word-aligned)"),
- addend_abs);
+ (unsigned long) addend_abs);
if ((addend_abs >> 2) > 0xff)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("bad offset 0x%08lX (must be an 8-bit number of words)"),
- addend_abs);
+ (unsigned long) addend_abs);
/* Extract the instruction. */
insn = md_chars_to_number (buf, INSN_SIZE);
bits of the instruction. */
insn &= 0xfffffff0;
insn |= addend_abs >> 2;
-
- /* Update the instruction. */
+
+ /* Update the instruction. */
md_number_to_chars (buf, insn, INSN_SIZE);
}
break;
+ case BFD_RELOC_ARM_V4BX:
+ /* This will need to go in the object file. */
+ fixP->fx_done = 0;
+ break;
+
case BFD_RELOC_UNUSED:
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
case BFD_RELOC_ARM_LDC_SB_G0:
case BFD_RELOC_ARM_LDC_SB_G1:
case BFD_RELOC_ARM_LDC_SB_G2:
+ case BFD_RELOC_ARM_V4BX:
code = fixp->fx_r_type;
break;
for (pool = list_of_pools; pool; pool = pool->next)
{
- /* Put it at the end of the relevent section. */
+ /* Put it at the end of the relevant section. */
subseg_set (pool->section, pool->sub_section);
#ifdef OBJ_ELF
arm_elf_change_section ();
#define OPTION_EL (OPTION_MD_BASE + 1)
#endif
#endif
+#define OPTION_FIX_V4BX (OPTION_MD_BASE + 2)
struct option md_longopts[] =
{
#ifdef OPTION_EL
{"EL", no_argument, NULL, OPTION_EL},
#endif
+ {"fix-v4bx", no_argument, NULL, OPTION_FIX_V4BX},
{NULL, no_argument, NULL, 0}
};
{"cortex-a8", ARM_ARCH_V7A, ARM_FEATURE(0, FPU_VFP_V3
| FPU_NEON_EXT_V1),
NULL},
+ {"cortex-a9", ARM_ARCH_V7A, ARM_FEATURE(0, FPU_VFP_V3
+ | FPU_NEON_EXT_V1),
+ NULL},
{"cortex-r4", ARM_ARCH_V7R, FPU_NONE, NULL},
{"cortex-m3", ARM_ARCH_V7M, FPU_NONE, NULL},
+ {"cortex-m1", ARM_ARCH_V6M, FPU_NONE, NULL},
/* ??? XSCALE is really an architecture. */
{"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
/* ??? iwmmxt is not a processor. */
{"armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP},
{"armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP},
{"armv6zkt2", ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
+ {"armv6-m", ARM_ARCH_V6M, FPU_ARCH_VFP},
{"armv7", ARM_ARCH_V7, FPU_ARCH_VFP},
/* The official spelling of the ARMv7 profile variants is the dashed form.
Accept the non-dashed form for compatibility with old toolchains. */
{"softvfp+vfp", FPU_ARCH_VFP_V2},
{"vfp", FPU_ARCH_VFP_V2},
{"vfp9", FPU_ARCH_VFP_V2},
- {"vfp3", FPU_ARCH_VFP_V3},
+ {"vfp3", FPU_ARCH_VFP_V3}, /* For backwards compatbility. */
{"vfp10", FPU_ARCH_VFP_V2},
{"vfp10-r0", FPU_ARCH_VFP_V1},
{"vfpxd", FPU_ARCH_VFP_V1xD},
+ {"vfpv2", FPU_ARCH_VFP_V2},
+ {"vfpv3", FPU_ARCH_VFP_V3},
+ {"vfpv3-d16", FPU_ARCH_VFP_V3D16},
{"arm1020t", FPU_ARCH_VFP_V1},
{"arm1020e", FPU_ARCH_VFP_V2},
{"arm1136jfs", FPU_ARCH_VFP_V2},
if (opt->name == NULL)
{
- as_bad (_("unknown architectural extnsion `%s'"), str);
+ as_bad (_("unknown architectural extension `%s'"), str);
return 0;
}
mcpu_cpu_opt = &opt->value;
mcpu_fpu_opt = &opt->default_fpu;
if (opt->canonical_name)
- strcpy(selected_cpu_name, opt->canonical_name);
+ strcpy (selected_cpu_name, opt->canonical_name);
else
{
int i;
{
march_cpu_opt = &opt->value;
march_fpu_opt = &opt->default_fpu;
- strcpy(selected_cpu_name, opt->name);
+ strcpy (selected_cpu_name, opt->name);
if (ext != NULL)
return arm_parse_extension (ext, &march_cpu_opt);
break;
#endif
+ case OPTION_FIX_V4BX:
+ fix_v4bx = TRUE;
+ break;
+
case 'a':
/* Listing option. Just ignore these, we don't support additional
ones. */
fprintf (fp, _("\
-EL assemble code for a little-endian cpu\n"));
#endif
+
+ fprintf (fp, _("\
+ --fix-v4bx Allow BX in ARMv4 code\n"));
}
{5, ARM_ARCH_V5TEJ},
{6, ARM_ARCH_V6},
{7, ARM_ARCH_V6Z},
- {8, ARM_ARCH_V6K},
- {9, ARM_ARCH_V6T2},
+ {9, ARM_ARCH_V6K},
+ {9, ARM_ARCH_V6M},
+ {8, ARM_ARCH_V6T2},
{10, ARM_ARCH_V7A},
{10, ARM_ARCH_V7R},
{10, ARM_ARCH_V7M},
char *p;
p = selected_cpu_name;
- if (strncmp(p, "armv", 4) == 0)
+ if (strncmp (p, "armv", 4) == 0)
{
int i;
-
+
p += 4;
for (i = 0; p[i]; i++)
p[i] = TOUPPER (p[i]);
bfd_elf_add_proc_attr_int (stdoutput, 7, 'A');
else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
bfd_elf_add_proc_attr_int (stdoutput, 7, 'R');
- else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m))
+ else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_m))
bfd_elf_add_proc_attr_int (stdoutput, 7, 'M');
/* Tag_ARM_ISA_use. */
if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_full))
bfd_elf_add_proc_attr_int (stdoutput, 9,
ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2) ? 2 : 1);
/* Tag_VFP_arch. */
- if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3)
+ if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_d32)
+ || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_d32))
+ bfd_elf_add_proc_attr_int (stdoutput, 10, 4);
+ else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3)
|| ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v3))
bfd_elf_add_proc_attr_int (stdoutput, 10, 3);
else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v2)
char saved_char;
name = input_line_pointer;
- while (*input_line_pointer && !ISSPACE(*input_line_pointer))
+ while (*input_line_pointer && !ISSPACE (*input_line_pointer))
input_line_pointer++;
saved_char = *input_line_pointer;
*input_line_pointer = 0;
mcpu_cpu_opt = &opt->value;
selected_cpu = opt->value;
if (opt->canonical_name)
- strcpy(selected_cpu_name, opt->canonical_name);
+ strcpy (selected_cpu_name, opt->canonical_name);
else
{
int i;
char *name;
name = input_line_pointer;
- while (*input_line_pointer && !ISSPACE(*input_line_pointer))
+ while (*input_line_pointer && !ISSPACE (*input_line_pointer))
input_line_pointer++;
saved_char = *input_line_pointer;
*input_line_pointer = 0;
{
mcpu_cpu_opt = &opt->value;
selected_cpu = opt->value;
- strcpy(selected_cpu_name, opt->name);
+ strcpy (selected_cpu_name, opt->name);
ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
char *name;
name = input_line_pointer;
- while (*input_line_pointer && !ISSPACE(*input_line_pointer))
+ while (*input_line_pointer && !ISSPACE (*input_line_pointer))
input_line_pointer++;
saved_char = *input_line_pointer;
*input_line_pointer = 0;
char *name;
name = input_line_pointer;
- while (*input_line_pointer && !ISSPACE(*input_line_pointer))
+ while (*input_line_pointer && !ISSPACE (*input_line_pointer))
input_line_pointer++;
saved_char = *input_line_pointer;
*input_line_pointer = 0;
-
+
for (opt = arm_fpus; opt->name != NULL; opt++)
if (streq (opt->name, name))
{