/* tc-arm.c -- Assemble for the ARM
- Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ Copyright (C) 1994-2019 Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
Modified by David Taylor (dtaylor@armltd.co.uk)
Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
unsigned sp_restored:1;
} unwind;
+/* Whether --fdpic was given. */
+static int arm_fdpic;
+
#endif /* OBJ_ELF */
/* Results from operand parsing worker functions. */
#define streq(a, b) (strcmp (a, b) == 0)
+/* Current set of feature bits available (CPU+FPU). Different from
+ selected_cpu + selected_fpu in case of autodetection since the CPU
+ feature bits are then all set. */
static arm_feature_set cpu_variant;
+/* Feature bits used in each execution state. Used to set build attribute
+ (in particular Tag_*_ISA_use) in CPU autodetection mode. */
static arm_feature_set arm_arch_used;
static arm_feature_set thumb_arch_used;
/* Variables that we set while parsing command-line options. Once all
options have been read we re-process these values to set the real
assembly flags. */
-static const arm_feature_set * legacy_cpu = NULL;
-static const arm_feature_set * legacy_fpu = NULL;
-
-static const arm_feature_set * mcpu_cpu_opt = NULL;
-static arm_feature_set * dyn_mcpu_ext_opt = NULL;
-static const arm_feature_set * mcpu_fpu_opt = NULL;
-static const arm_feature_set * march_cpu_opt = NULL;
-static arm_feature_set * dyn_march_ext_opt = NULL;
-static const arm_feature_set * march_fpu_opt = NULL;
-static const arm_feature_set * mfpu_opt = NULL;
-static const arm_feature_set * object_arch = NULL;
+
+/* CPU and FPU feature bits set for legacy CPU and FPU options (eg. -marm1
+ instead of -mcpu=arm1). */
+static const arm_feature_set *legacy_cpu = NULL;
+static const arm_feature_set *legacy_fpu = NULL;
+
+/* CPU, extension and FPU feature bits selected by -mcpu. */
+static const arm_feature_set *mcpu_cpu_opt = NULL;
+static arm_feature_set *mcpu_ext_opt = NULL;
+static const arm_feature_set *mcpu_fpu_opt = NULL;
+
+/* CPU, extension and FPU feature bits selected by -march. */
+static const arm_feature_set *march_cpu_opt = NULL;
+static arm_feature_set *march_ext_opt = NULL;
+static const arm_feature_set *march_fpu_opt = NULL;
+
+/* Feature bits selected by -mfpu. */
+static const arm_feature_set *mfpu_opt = NULL;
/* Constants for known architecture features. */
static const arm_feature_set fpu_default = FPU_DEFAULT;
static const arm_feature_set arm_ext_v6 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6);
static const arm_feature_set arm_ext_v6k = ARM_FEATURE_CORE_LOW (ARM_EXT_V6K);
static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6T2);
+/* Only for compatability of hint instructions. */
+static const arm_feature_set arm_ext_v6k_v6t2 =
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V6K | ARM_EXT_V6T2);
static const arm_feature_set arm_ext_v6_notm =
ARM_FEATURE_CORE_LOW (ARM_EXT_V6_NOTM);
static const arm_feature_set arm_ext_v6_dsp =
static const arm_feature_set arm_ext_v8m = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M);
static const arm_feature_set arm_ext_v8m_main =
ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN);
+static const arm_feature_set arm_ext_v8_1m_main =
+ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN);
/* Instructions in ARMv8-M only found in M profile architectures. */
static const arm_feature_set arm_ext_v8m_m_only =
ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M | ARM_EXT2_V8M_MAIN);
ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_2A);
static const arm_feature_set arm_ext_v8_3 =
ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A);
+static const arm_feature_set arm_ext_sb =
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB);
+static const arm_feature_set arm_ext_predres =
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES);
static const arm_feature_set arm_arch_any = ARM_ANY;
#ifdef OBJ_ELF
ARM_FEATURE_COPROC (FPU_NEON_EXT_V1);
static const arm_feature_set fpu_vfp_v3_or_neon_ext =
ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3);
+static const arm_feature_set mve_ext =
+ ARM_FEATURE_COPROC (FPU_MVE);
+static const arm_feature_set mve_fp_ext =
+ ARM_FEATURE_COPROC (FPU_MVE_FP);
#ifdef OBJ_ELF
static const arm_feature_set fpu_vfp_fp16 =
ARM_FEATURE_COPROC (FPU_VFP_EXT_FP16);
ARM_FEATURE_COPROC (FPU_NEON_EXT_DOTPROD);
static int mfloat_abi_opt = -1;
-/* Record user cpu selection for object attributes. */
+/* Architecture feature bits selected by the last -mcpu/-march or .cpu/.arch
+ directive. */
+static arm_feature_set selected_arch = ARM_ARCH_NONE;
+/* Extension feature bits selected by the last -mcpu/-march or .arch_extension
+ directive. */
+static arm_feature_set selected_ext = ARM_ARCH_NONE;
+/* Feature bits selected by the last -mcpu/-march or by the combination of the
+ last .cpu/.arch directive .arch_extension directives since that
+ directive. */
static arm_feature_set selected_cpu = ARM_ARCH_NONE;
+/* FPU feature bits selected by the last -mfpu or .fpu directive. */
+static arm_feature_set selected_fpu = FPU_NONE;
+/* Feature bits selected by the last .object_arch directive. */
+static arm_feature_set selected_object_arch = ARM_ARCH_NONE;
/* Must be long enough to hold any of the names in arm_cpus. */
static char selected_cpu_name[20];
/* The maximum number of operands we need. */
#define ARM_IT_MAX_OPERANDS 6
+#define ARM_IT_MAX_RELOCS 3
struct arm_it
{
bfd_reloc_code_real_type type;
expressionS exp;
int pc_rel;
- } reloc;
+ } relocs[ARM_IT_MAX_RELOCS];
enum it_instruction_type it_insn_type;
"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
};
-/* Number of littlenums required to hold an extended precision number. */
-#define MAX_LITTLENUMS 6
-
LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
#define FAIL (-1)
#define BAD_THUMB32 _("instruction not supported in Thumb16 mode")
#define BAD_ADDR_MODE _("instruction does not accept this addressing mode");
#define BAD_BRANCH _("branch must be last instruction in IT block")
+#define BAD_BRANCH_OFF _("branch out of range or not a multiple of 2")
#define BAD_NOT_IT _("instruction not allowed in IT block")
#define BAD_FPU _("selected FPU does not support instruction")
#define BAD_OUT_IT _("thumb conditional instruction should be in IT block")
my_get_expression (expressionS * ep, char ** str, int prefix_mode)
{
char * save_in;
- segT seg;
/* In unified syntax, all prefixes are optional. */
if (unified_syntax)
save_in = input_line_pointer;
input_line_pointer = *str;
in_my_get_expression = TRUE;
- seg = expression (ep);
+ expression (ep);
in_my_get_expression = FALSE;
if (ep->X_op == O_illegal || ep->X_op == O_absent)
return 1;
}
-#ifdef OBJ_AOUT
- if (seg != absolute_section
- && seg != text_section
- && seg != data_section
- && seg != bss_section
- && seg != undefined_section)
- {
- inst.error = _("bad segment");
- *str = input_line_pointer;
- 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
we can't establish a line number later on. Big numbers are never valid
in instructions, which is where this routine is always called. */
return reg->number;
}
-/* Like arm_reg_parse, but allow allow the following extra features:
+/* Like arm_reg_parse, but also allow the following extra features:
- If RTYPE is non-zero, return the (possibly restricted) type of the
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
return reg * 16 + atype.index;
}
+/* Types of registers in a list. */
+
+enum reg_list_els
+{
+ REGLIST_RN,
+ REGLIST_CLRM,
+ REGLIST_VFP_S,
+ REGLIST_VFP_S_VPR,
+ REGLIST_VFP_D,
+ REGLIST_VFP_D_VPR,
+ REGLIST_NEON_D
+};
+
/* Parse an ARM register list. Returns the bitmask, or FAIL. */
static long
-parse_reg_list (char ** strp)
+parse_reg_list (char ** strp, enum reg_list_els etype)
{
- char * str = * strp;
- long range = 0;
- int another_range;
+ char *str = *strp;
+ long range = 0;
+ int another_range;
+
+ gas_assert (etype == REGLIST_RN || etype == REGLIST_CLRM);
/* We come back here if we get ranges concatenated by '+' or '|'. */
do
do
{
int reg;
+ const char apsr_str[] = "apsr";
+ int apsr_str_len = strlen (apsr_str);
- if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL)
+ reg = arm_reg_parse (&str, REGLIST_RN);
+ if (etype == REGLIST_CLRM)
{
- first_error (_(reg_expected_msgs[REG_TYPE_RN]));
- return FAIL;
+ if (reg == REG_SP || reg == REG_PC)
+ reg = FAIL;
+ else if (reg == FAIL
+ && !strncasecmp (str, apsr_str, apsr_str_len)
+ && !ISALPHA (*(str + apsr_str_len)))
+ {
+ reg = 15;
+ str += apsr_str_len;
+ }
+
+ if (reg == FAIL)
+ {
+ first_error (_("r0-r12, lr or APSR expected"));
+ return FAIL;
+ }
+ }
+ else /* etype == REGLIST_RN. */
+ {
+ if (reg == FAIL)
+ {
+ first_error (_(reg_expected_msgs[REGLIST_RN]));
+ return FAIL;
+ }
}
if (in_range)
return FAIL;
}
}
- else
+ else if (etype == REGLIST_RN)
{
expressionS exp;
}
else
{
- if (inst.reloc.type != 0)
+ if (inst.relocs[0].type != 0)
{
inst.error = _("expression too complex");
return FAIL;
}
- memcpy (&inst.reloc.exp, &exp, sizeof (expressionS));
- inst.reloc.type = BFD_RELOC_ARM_MULTI;
- inst.reloc.pc_rel = 0;
+ memcpy (&inst.relocs[0].exp, &exp, sizeof (expressionS));
+ inst.relocs[0].type = BFD_RELOC_ARM_MULTI;
+ inst.relocs[0].pc_rel = 0;
}
}
return range;
}
-/* Types of registers in a list. */
-
-enum reg_list_els
-{
- REGLIST_VFP_S,
- REGLIST_VFP_D,
- REGLIST_NEON_D
-};
-
/* Parse a VFP register list. If the string is invalid return FAIL.
Otherwise return the number of registers, and set PBASE to the first
register. Parses registers of type ETYPE.
bug. */
static int
-parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
+parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype,
+ bfd_boolean *partial_match)
{
char *str = *ccp;
int base_reg;
int warned = 0;
unsigned long mask = 0;
int i;
+ bfd_boolean vpr_seen = FALSE;
+ bfd_boolean expect_vpr =
+ (etype == REGLIST_VFP_S_VPR) || (etype == REGLIST_VFP_D_VPR);
if (skip_past_char (&str, '{') == FAIL)
{
switch (etype)
{
case REGLIST_VFP_S:
+ case REGLIST_VFP_S_VPR:
regtype = REG_TYPE_VFS;
max_regs = 32;
break;
case REGLIST_VFP_D:
+ case REGLIST_VFP_D_VPR:
regtype = REG_TYPE_VFD;
break;
case REGLIST_NEON_D:
regtype = REG_TYPE_NDQ;
break;
+
+ default:
+ gas_assert (0);
}
- if (etype != REGLIST_VFP_S)
+ if (etype != REGLIST_VFP_S && etype != REGLIST_VFP_S_VPR)
{
/* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant. */
if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
}
base_reg = max_regs;
+ *partial_match = FALSE;
do
{
int setmask = 1, addregs = 1;
+ const char vpr_str[] = "vpr";
+ int vpr_str_len = strlen (vpr_str);
new_base = arm_typed_reg_parse (&str, regtype, ®type, NULL);
- if (new_base == FAIL)
+ if (expect_vpr)
+ {
+ if (new_base == FAIL
+ && !strncasecmp (str, vpr_str, vpr_str_len)
+ && !ISALPHA (*(str + vpr_str_len))
+ && !vpr_seen)
+ {
+ vpr_seen = TRUE;
+ str += vpr_str_len;
+ if (count == 0)
+ base_reg = 0; /* Canonicalize VPR only on d0 with 0 regs. */
+ }
+ else if (vpr_seen)
+ {
+ first_error (_("VPR expected last"));
+ return FAIL;
+ }
+ else if (new_base == FAIL)
+ {
+ if (regtype == REG_TYPE_VFS)
+ first_error (_("VFP single precision register or VPR "
+ "expected"));
+ else /* regtype == REG_TYPE_VFD. */
+ first_error (_("VFP/Neon double precision register or VPR "
+ "expected"));
+ return FAIL;
+ }
+ }
+ else if (new_base == FAIL)
{
first_error (_(reg_expected_msgs[regtype]));
return FAIL;
}
+ *partial_match = TRUE;
+ if (vpr_seen)
+ continue;
+
if (new_base >= max_regs)
{
first_error (_("register out of range in list"));
return FAIL;
}
- if ((mask >> new_base) != 0 && ! warned)
+ if ((mask >> new_base) != 0 && ! warned && !vpr_seen)
{
as_tsktsk (_("register list not in ascending order"));
warned = 1;
str++;
/* Sanity check -- should have raised a parse error above. */
- if (count == 0 || count > max_regs)
+ if ((!vpr_seen && count == 0) || count > max_regs)
abort ();
*pbase = base_reg;
+ if (expect_vpr && !vpr_seen)
+ {
+ first_error (_("VPR expected last"));
+ return FAIL;
+ }
+
/* Final test -- the registers must be consecutive. */
mask >>= base_reg;
for (i = 0; i < count; i++)
{
imm1 = inst.operands[1].imm;
imm2 = (inst.operands[1].regisimm ? inst.operands[1].reg
- : inst.reloc.exp.X_unsigned ? 0
+ : inst.relocs[0].exp.X_unsigned ? 0
: ((bfd_int64_t) inst.operands[1].imm) >> 32);
if (target_big_endian)
{
{
if (nbytes == 4)
{
- if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
- && (inst.reloc.exp.X_op == O_constant)
+ if ((pool->literals[entry].X_op == inst.relocs[0].exp.X_op)
+ && (inst.relocs[0].exp.X_op == O_constant)
&& (pool->literals[entry].X_add_number
- == inst.reloc.exp.X_add_number)
+ == inst.relocs[0].exp.X_add_number)
&& (pool->literals[entry].X_md == nbytes)
&& (pool->literals[entry].X_unsigned
- == inst.reloc.exp.X_unsigned))
+ == inst.relocs[0].exp.X_unsigned))
break;
- if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
- && (inst.reloc.exp.X_op == O_symbol)
+ if ((pool->literals[entry].X_op == inst.relocs[0].exp.X_op)
+ && (inst.relocs[0].exp.X_op == O_symbol)
&& (pool->literals[entry].X_add_number
- == inst.reloc.exp.X_add_number)
+ == inst.relocs[0].exp.X_add_number)
&& (pool->literals[entry].X_add_symbol
- == inst.reloc.exp.X_add_symbol)
+ == inst.relocs[0].exp.X_add_symbol)
&& (pool->literals[entry].X_op_symbol
- == inst.reloc.exp.X_op_symbol)
+ == inst.relocs[0].exp.X_op_symbol)
&& (pool->literals[entry].X_md == nbytes))
break;
}
&& (pool->literals[entry].X_op == O_constant)
&& (pool->literals[entry].X_add_number == (offsetT) imm1)
&& (pool->literals[entry].X_unsigned
- == inst.reloc.exp.X_unsigned)
+ == inst.relocs[0].exp.X_unsigned)
&& (pool->literals[entry + 1].X_op == O_constant)
&& (pool->literals[entry + 1].X_add_number == (offsetT) imm2)
&& (pool->literals[entry + 1].X_unsigned
- == inst.reloc.exp.X_unsigned))
+ == inst.relocs[0].exp.X_unsigned))
break;
padding_slot_p = ((pool->literals[entry].X_md >> 8) == PADDING_SLOT);
We also check to make sure the literal operand is a
constant number. */
- if (!(inst.reloc.exp.X_op == O_constant
- || inst.reloc.exp.X_op == O_big))
+ if (!(inst.relocs[0].exp.X_op == O_constant
+ || inst.relocs[0].exp.X_op == O_big))
{
inst.error = _("invalid type for literal pool");
return FAIL;
return FAIL;
}
- pool->literals[entry] = inst.reloc.exp;
+ pool->literals[entry] = inst.relocs[0].exp;
pool->literals[entry].X_op = O_constant;
pool->literals[entry].X_add_number = 0;
pool->literals[entry++].X_md = (PADDING_SLOT << 8) | 4;
return FAIL;
}
- pool->literals[entry] = inst.reloc.exp;
+ pool->literals[entry] = inst.relocs[0].exp;
pool->literals[entry].X_op = O_constant;
pool->literals[entry].X_add_number = imm1;
- pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned;
+ pool->literals[entry].X_unsigned = inst.relocs[0].exp.X_unsigned;
pool->literals[entry++].X_md = 4;
- pool->literals[entry] = inst.reloc.exp;
+ pool->literals[entry] = inst.relocs[0].exp;
pool->literals[entry].X_op = O_constant;
pool->literals[entry].X_add_number = imm2;
- pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned;
+ pool->literals[entry].X_unsigned = inst.relocs[0].exp.X_unsigned;
pool->literals[entry].X_md = 4;
pool->alignment = 3;
pool->next_free_entry += 1;
}
else
{
- pool->literals[entry] = inst.reloc.exp;
+ pool->literals[entry] = inst.relocs[0].exp;
pool->literals[entry].X_md = 4;
}
}
else if (padding_slot_p)
{
- pool->literals[entry] = inst.reloc.exp;
+ pool->literals[entry] = inst.relocs[0].exp;
pool->literals[entry].X_md = nbytes;
}
- inst.reloc.exp.X_op = O_symbol;
- inst.reloc.exp.X_add_number = pool_size;
- inst.reloc.exp.X_add_symbol = pool->symbol;
+ inst.relocs[0].exp.X_op = O_symbol;
+ inst.relocs[0].exp.X_add_number = pool_size;
+ inst.relocs[0].exp.X_add_symbol = pool->symbol;
return SUCCESS;
}
long range;
int n;
- range = parse_reg_list (&input_line_pointer);
+ range = parse_reg_list (&input_line_pointer, REGLIST_RN);
if (range == FAIL)
{
as_bad (_("expected register list"));
valueT op;
int num_vfpv3_regs = 0;
int num_regs_below_16;
+ bfd_boolean partial_match;
- count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D);
+ count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D,
+ &partial_match);
if (count == FAIL)
{
as_bad (_("expected register list"));
int count;
unsigned int reg;
valueT op;
+ bfd_boolean partial_match;
- count = parse_vfp_reg_list (&input_line_pointer, ®, REGLIST_VFP_D);
+ count = parse_vfp_reg_list (&input_line_pointer, ®, REGLIST_VFP_D,
+ &partial_match);
if (count == FAIL)
{
as_bad (_("expected register list"));
{
int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
- if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
+ if (tag >= 0 && tag < NUM_KNOWN_OBJ_ATTRIBUTES)
attributes_set_explicitly[tag] = 1;
}
{"4byte", cons, 4},
{"8byte", cons, 8},
/* These are used for dwarf2. */
- { "file", (void (*) (int)) dwarf2_directive_file, 0 },
+ { "file", dwarf2_directive_file, 0 },
{ "loc", dwarf2_directive_loc, 0 },
{ "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
#endif
inst.operands[i].imm = reg;
inst.operands[i].immisreg = 1;
}
- else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+ else if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX))
return FAIL;
}
inst.operands[i].shift_kind = shift;
inst.operands[i].isreg = 1;
/* parse_shift will override this if appropriate */
- inst.reloc.exp.X_op = O_constant;
- inst.reloc.exp.X_add_number = 0;
+ inst.relocs[0].exp.X_op = O_constant;
+ inst.relocs[0].exp.X_add_number = 0;
if (skip_past_comma (str) == FAIL)
return SUCCESS;
return parse_shift (str, i, NO_SHIFT_RESTRICT);
}
- if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX))
+ if (my_get_expression (&inst.relocs[0].exp, str, GE_IMM_PREFIX))
return FAIL;
if (skip_past_comma (str) == SUCCESS)
if (my_get_expression (&exp, str, GE_NO_PREFIX))
return FAIL;
- if (exp.X_op != O_constant || inst.reloc.exp.X_op != O_constant)
+ if (exp.X_op != O_constant || inst.relocs[0].exp.X_op != O_constant)
{
inst.error = _("constant expression expected");
return FAIL;
inst.error = _("invalid rotation");
return FAIL;
}
- if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255)
+ if (inst.relocs[0].exp.X_add_number < 0
+ || inst.relocs[0].exp.X_add_number > 255)
{
inst.error = _("invalid constant");
return FAIL;
}
/* Encode as specified. */
- inst.operands[i].imm = inst.reloc.exp.X_add_number | value << 7;
+ inst.operands[i].imm = inst.relocs[0].exp.X_add_number | value << 7;
return SUCCESS;
}
- inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
- inst.reloc.pc_rel = 0;
+ inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE;
+ inst.relocs[0].pc_rel = 0;
return SUCCESS;
}
/* We now have the group relocation table entry corresponding to
the name in the assembler source. Next, we parse the expression. */
- if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX))
+ if (my_get_expression (&inst.relocs[0].exp, str, GE_NO_PREFIX))
return PARSE_OPERAND_FAIL_NO_BACKTRACK;
/* Record the relocation type (always the ALU variant here). */
- inst.reloc.type = (bfd_reloc_code_real_type) entry->alu_code;
- gas_assert (inst.reloc.type != 0);
+ inst.relocs[0].type = (bfd_reloc_code_real_type) entry->alu_code;
+ gas_assert (inst.relocs[0].type != 0);
return PARSE_OPERAND_SUCCESS;
}
}
/* Parse all forms of an ARM address expression. Information is written
- to inst.operands[i] and/or inst.reloc.
+ to inst.operands[i] and/or inst.relocs[0].
Preindexed addressing (.preind=1):
- [Rn, #offset] .reg=Rn .reloc.exp=offset
+ [Rn, #offset] .reg=Rn .relocs[0].exp=offset
[Rn, +/-Rm] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
[Rn, +/-Rm, shift] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
- .shift_kind=shift .reloc.exp=shift_imm
+ .shift_kind=shift .relocs[0].exp=shift_imm
These three may have a trailing ! which causes .writeback to be set also.
Postindexed addressing (.postind=1, .writeback=1):
- [Rn], #offset .reg=Rn .reloc.exp=offset
+ [Rn], #offset .reg=Rn .relocs[0].exp=offset
[Rn], +/-Rm .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
[Rn], +/-Rm, shift .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
- .shift_kind=shift .reloc.exp=shift_imm
+ .shift_kind=shift .relocs[0].exp=shift_imm
Unindexed addressing (.preind=0, .postind=0):
Other:
[Rn]{!} shorthand for [Rn,#0]{!}
- =immediate .isreg=0 .reloc.exp=immediate
- label .reg=PC .reloc.pc_rel=1 .reloc.exp=label
+ =immediate .isreg=0 .relocs[0].exp=immediate
+ label .reg=PC .relocs[0].pc_rel=1 .relocs[0].exp=label
It is the caller's responsibility to check for addressing modes not
- supported by the instruction, and to set inst.reloc.type. */
+ supported by the instruction, and to set inst.relocs[0].type. */
static parse_operand_result
parse_address_main (char **str, int i, int group_relocations,
if (skip_past_char (&p, '=') == FAIL)
{
/* Bare address - translate to PC-relative offset. */
- inst.reloc.pc_rel = 1;
+ inst.relocs[0].pc_rel = 1;
inst.operands[i].reg = REG_PC;
inst.operands[i].isreg = 1;
inst.operands[i].preind = 1;
- if (my_get_expression (&inst.reloc.exp, &p, GE_OPT_PREFIX_BIG))
+ if (my_get_expression (&inst.relocs[0].exp, &p, GE_OPT_PREFIX_BIG))
return PARSE_OPERAND_FAIL;
}
- else if (parse_big_immediate (&p, i, &inst.reloc.exp,
+ else if (parse_big_immediate (&p, i, &inst.relocs[0].exp,
/*allow_symbol_p=*/TRUE))
return PARSE_OPERAND_FAIL;
/* We now have the group relocation table entry corresponding to
the name in the assembler source. Next, we parse the
expression. */
- if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
+ if (my_get_expression (&inst.relocs[0].exp, &p, GE_NO_PREFIX))
return PARSE_OPERAND_FAIL_NO_BACKTRACK;
/* Record the relocation type. */
switch (group_type)
{
case GROUP_LDR:
- inst.reloc.type = (bfd_reloc_code_real_type) entry->ldr_code;
+ inst.relocs[0].type
+ = (bfd_reloc_code_real_type) entry->ldr_code;
break;
case GROUP_LDRS:
- inst.reloc.type = (bfd_reloc_code_real_type) entry->ldrs_code;
+ inst.relocs[0].type
+ = (bfd_reloc_code_real_type) entry->ldrs_code;
break;
case GROUP_LDC:
- inst.reloc.type = (bfd_reloc_code_real_type) entry->ldc_code;
+ inst.relocs[0].type
+ = (bfd_reloc_code_real_type) entry->ldc_code;
break;
default:
gas_assert (0);
}
- if (inst.reloc.type == 0)
+ if (inst.relocs[0].type == 0)
{
inst.error = _("this group relocation is not allowed on this instruction");
return PARSE_OPERAND_FAIL_NO_BACKTRACK;
{
char *q = p;
- if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+ if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX))
return PARSE_OPERAND_FAIL;
/* If the offset is 0, find out if it's a +0 or -0. */
- if (inst.reloc.exp.X_op == O_constant
- && inst.reloc.exp.X_add_number == 0)
+ if (inst.relocs[0].exp.X_op == O_constant
+ && inst.relocs[0].exp.X_add_number == 0)
{
skip_whitespace (q);
if (*q == '#')
inst.operands[i].negative = 0;
p--;
}
- if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+ if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX))
return PARSE_OPERAND_FAIL;
/* If the offset is 0, find out if it's a +0 or -0. */
- if (inst.reloc.exp.X_op == O_constant
- && inst.reloc.exp.X_add_number == 0)
+ if (inst.relocs[0].exp.X_op == O_constant
+ && inst.relocs[0].exp.X_add_number == 0)
{
skip_whitespace (q);
if (*q == '#')
if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0)
{
inst.operands[i].preind = 1;
- inst.reloc.exp.X_op = O_constant;
- inst.reloc.exp.X_add_number = 0;
+ inst.relocs[0].exp.X_op = O_constant;
+ inst.relocs[0].exp.X_add_number = 0;
}
*str = p;
return PARSE_OPERAND_SUCCESS;
p = *str;
skip_past_char (&p, '#');
if (strncasecmp (p, ":lower16:", 9) == 0)
- inst.reloc.type = BFD_RELOC_ARM_MOVW;
+ inst.relocs[0].type = BFD_RELOC_ARM_MOVW;
else if (strncasecmp (p, ":upper16:", 9) == 0)
- inst.reloc.type = BFD_RELOC_ARM_MOVT;
+ inst.relocs[0].type = BFD_RELOC_ARM_MOVT;
- if (inst.reloc.type != BFD_RELOC_UNUSED)
+ if (inst.relocs[0].type != BFD_RELOC_UNUSED)
{
p += 9;
skip_whitespace (p);
}
- if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
+ if (my_get_expression (&inst.relocs[0].exp, &p, GE_NO_PREFIX))
return FAIL;
- if (inst.reloc.type == BFD_RELOC_UNUSED)
+ if (inst.relocs[0].type == BFD_RELOC_UNUSED)
{
- if (inst.reloc.exp.X_op != O_constant)
+ if (inst.relocs[0].exp.X_op != O_constant)
{
inst.error = _("constant expression expected");
return FAIL;
}
- if (inst.reloc.exp.X_add_number < 0
- || inst.reloc.exp.X_add_number > 0xffff)
+ if (inst.relocs[0].exp.X_add_number < 0
+ || inst.relocs[0].exp.X_add_number > 0xffff)
{
inst.error = _("immediate value out of range");
return FAIL;
return FAIL;
}
+static int
+parse_sys_vldr_vstr (char **str)
+{
+ unsigned i;
+ int val = FAIL;
+ struct {
+ const char *name;
+ int regl;
+ int regh;
+ } sysregs[] = {
+ {"FPSCR", 0x1, 0x0},
+ {"FPSCR_nzcvqc", 0x2, 0x0},
+ {"VPR", 0x4, 0x1},
+ {"P0", 0x5, 0x1},
+ {"FPCXTNS", 0x6, 0x1},
+ {"FPCXTS", 0x7, 0x1}
+ };
+ char *op_end = strchr (*str, ',');
+ size_t op_strlen = op_end - *str;
+
+ for (i = 0; i < sizeof (sysregs) / sizeof (sysregs[0]); i++)
+ {
+ if (!strncmp (*str, sysregs[i].name, op_strlen))
+ {
+ val = sysregs[i].regl | (sysregs[i].regh << 3);
+ *str = op_end;
+ break;
+ }
+ }
+
+ return val;
+}
+
/* Parse the flags argument to CPSI[ED]. Returns FAIL on error, or a
value suitable for splatting into the AIF field of the instruction. */
ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, *feature);
}
-/* If the given feature available in the selected CPU, mark it as used.
- Returns TRUE iff feature is available. */
+/* If the given feature is currently allowed, mark it as used and return TRUE.
+ Return FALSE otherwise. */
static bfd_boolean
mark_feature_used (const arm_feature_set *feature)
{
- /* Ensure the option is valid on the current architecture. */
+ /* Ensure the option is currently allowed. */
if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
return FALSE;
- /* Add the appropriate architecture feature for the barrier option used.
- */
+ /* Add the appropriate architecture feature for the barrier option used. */
record_feature_use (feature);
return TRUE;
{
if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL)
return FAIL;
- if (inst.reloc.exp.X_add_number != 1)
+ if (inst.relocs[0].exp.X_add_number != 1)
{
inst.error = _("invalid shift");
return FAIL;
OP_RIWG, /* iWMMXt wCG register */
OP_RXA, /* XScale accumulator register */
+ /* New operands for Armv8.1-M Mainline. */
+ OP_LR, /* ARM LR register */
+ OP_RRnpcsp_I32, /* ARM register (no BadReg) or literal 1 .. 32 */
+
OP_REGLST, /* ARM register list */
+ OP_CLRMLST, /* CLRM register list */
OP_VRSLST, /* VFP single-precision register list */
OP_VRDLST, /* VFP double-precision register list */
OP_VRSDLST, /* VFP single or double-precision register list (& quad) */
OP_NRDLST, /* Neon double-precision register list (d0-d31, qN aliases) */
OP_NSTRLST, /* Neon element/structure list */
+ OP_VRSDVLST, /* VFP single or double-precision register list and VPR */
OP_RNDQ_I0, /* Neon D or Q reg, or immediate zero. */
OP_RVSD_I0, /* VFP S or D reg, or immediate zero. */
OP_RNDQ_Ibig, /* Neon D or Q reg, or big immediate for logic and VMVN. */
OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift. */
OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2. */
+ OP_VLDR, /* VLDR operand. */
OP_I0, /* immediate zero */
OP_I7, /* immediate value 0 .. 7 */
OP_EXP, /* arbitrary expression */
OP_EXPi, /* same, with optional immediate prefix */
OP_EXPr, /* same, with optional relocation suffix */
+ OP_EXPs, /* same, with optional non-first operand relocation suffix */
OP_HALF, /* 0 .. 65535 or low/high reloc. */
OP_IROT1, /* VCADD rotate immediate: 90, 270. */
OP_IROT2, /* VCMLA rotate immediate: 0, 90, 180, 270. */
OP_oI255c, /* curly-brace enclosed, 0 .. 255 */
OP_oRR, /* ARM register */
+ OP_oLR, /* ARM LR register */
OP_oRRnpc, /* ARM register, not the PC */
OP_oRRnpcsp, /* ARM register, neither the PC nor the SP (a.k.a. BadReg) */
OP_oRRw, /* ARM register, not r15, optional trailing ! */
enum arm_reg_type rtype;
parse_operand_result result;
unsigned int op_parse_code;
+ bfd_boolean partial_match;
#define po_char_or_fail(chr) \
do \
case OP_RRnpc:
case OP_RRnpcsp:
case OP_oRR:
+ case OP_LR:
+ case OP_oLR:
case OP_RR: po_reg_or_fail (REG_TYPE_RN); break;
case OP_RCP: po_reg_or_fail (REG_TYPE_CP); break;
case OP_RCN: po_reg_or_fail (REG_TYPE_CN); break;
/* Expressions */
case OP_EXPi: EXPi:
- po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+ po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str,
GE_OPT_PREFIX));
break;
case OP_EXP:
- po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+ po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str,
GE_NO_PREFIX));
break;
case OP_EXPr: EXPr:
- po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+ po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str,
GE_NO_PREFIX));
- if (inst.reloc.exp.X_op == O_symbol)
+ if (inst.relocs[0].exp.X_op == O_symbol)
{
val = parse_reloc (&str);
if (val == -1)
}
break;
+ case OP_EXPs:
+ po_misc_or_fail (my_get_expression (&inst.relocs[i].exp, &str,
+ GE_NO_PREFIX));
+ if (inst.relocs[i].exp.X_op == O_symbol)
+ {
+ inst.operands[i].hasreloc = 1;
+ }
+ else if (inst.relocs[i].exp.X_op == O_constant)
+ {
+ inst.operands[i].imm = inst.relocs[i].exp.X_add_number;
+ inst.operands[i].hasreloc = 0;
+ }
+ break;
+
/* Operand for MOVW or MOVT. */
case OP_HALF:
po_misc_or_fail (parse_half (&str));
val = parse_psr (&str, op_parse_code == OP_wPSR);
break;
+ case OP_VLDR:
+ po_reg_or_goto (REG_TYPE_VFSD, try_sysreg);
+ break;
+ try_sysreg:
+ val = parse_sys_vldr_vstr (&str);
+ break;
+
case OP_APSR_RR:
po_reg_or_goto (REG_TYPE_RN, try_apsr);
break;
/* Register lists. */
case OP_REGLST:
- val = parse_reg_list (&str);
+ val = parse_reg_list (&str, REGLIST_RN);
if (*str == '^')
{
inst.operands[i].writeback = 1;
}
break;
+ case OP_CLRMLST:
+ val = parse_reg_list (&str, REGLIST_CLRM);
+ break;
+
case OP_VRSLST:
- val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S,
+ &partial_match);
break;
case OP_VRDLST:
- val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D,
+ &partial_match);
break;
case OP_VRSDLST:
/* Allow Q registers too. */
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
- REGLIST_NEON_D);
+ REGLIST_NEON_D, &partial_match);
if (val == FAIL)
{
inst.error = NULL;
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
- REGLIST_VFP_S);
+ REGLIST_VFP_S, &partial_match);
+ inst.operands[i].issingle = 1;
+ }
+ break;
+
+ case OP_VRSDVLST:
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+ REGLIST_VFP_D_VPR, &partial_match);
+ if (val == FAIL && !partial_match)
+ {
+ inst.error = NULL;
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+ REGLIST_VFP_S_VPR, &partial_match);
inst.operands[i].issingle = 1;
}
break;
case OP_NRDLST:
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
- REGLIST_NEON_D);
+ REGLIST_NEON_D, &partial_match);
break;
case OP_NSTRLST:
inst.error = BAD_PC;
break;
+ case OP_VLDR:
+ if (inst.operands[i].isreg)
+ break;
+ /* fall through. */
case OP_CPSF:
case OP_ENDI:
case OP_oROR:
case OP_COND:
case OP_oBARRIER_I15:
case OP_REGLST:
+ case OP_CLRMLST:
case OP_VRSLST:
case OP_VRDLST:
case OP_VRSDLST:
+ case OP_VRSDVLST:
case OP_NRDLST:
case OP_NSTRLST:
if (val == FAIL)
inst.operands[i].imm = val;
break;
+ case OP_LR:
+ case OP_oLR:
+ if (inst.operands[i].reg != REG_LR)
+ inst.error = _("operand must be LR register");
+ break;
+
default:
break;
}
inst.instruction |= inst.operands[i].imm << 8;
}
else
- inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM;
}
}
else
{
inst.instruction |= INST_IMMEDIATE;
- if (inst.reloc.type != BFD_RELOC_ARM_IMMEDIATE)
+ if (inst.relocs[0].type != BFD_RELOC_ARM_IMMEDIATE)
inst.instruction |= inst.operands[i].imm;
}
}
else
{
inst.instruction |= inst.operands[i].shift_kind << 5;
- inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM;
}
}
}
- else /* immediate offset in inst.reloc */
+ else /* immediate offset in inst.relocs[0] */
{
- if (is_pc && !inst.reloc.pc_rel)
+ if (is_pc && !inst.relocs[0].pc_rel)
{
const bfd_boolean is_load = ((inst.instruction & LOAD_BIT) != 0);
as_tsktsk (_("use of PC in this instruction is deprecated"));
}
- if (inst.reloc.type == BFD_RELOC_UNUSED)
+ if (inst.relocs[0].type == BFD_RELOC_UNUSED)
{
/* Prefer + for zero encoded value. */
if (!inst.operands[i].negative)
inst.instruction |= INDEX_UP;
- inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_OFFSET_IMM;
}
}
}
if (!inst.operands[i].negative)
inst.instruction |= INDEX_UP;
}
- else /* immediate offset in inst.reloc */
+ else /* immediate offset in inst.relocs[0] */
{
- constraint ((inst.operands[i].reg == REG_PC && !inst.reloc.pc_rel
+ constraint ((inst.operands[i].reg == REG_PC && !inst.relocs[0].pc_rel
&& inst.operands[i].writeback),
BAD_PC_WRITEBACK);
inst.instruction |= HWOFFSET_IMM;
- if (inst.reloc.type == BFD_RELOC_UNUSED)
+ if (inst.relocs[0].type == BFD_RELOC_UNUSED)
{
/* Prefer + for zero encoded value. */
if (!inst.operands[i].negative)
inst.instruction |= INDEX_UP;
- inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
+ inst.relocs[0].type = BFD_RELOC_ARM_OFFSET_IMM8;
}
}
}
static void do_vfp_nsyn_opcode (const char *);
-/* inst.reloc.exp describes an "=expr" load pseudo-operation.
+/* inst.relocs[0].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
return TRUE; if it can't, convert inst.instruction to a literal-pool
return TRUE;
}
- if (inst.reloc.exp.X_op != O_constant
- && inst.reloc.exp.X_op != O_symbol
- && inst.reloc.exp.X_op != O_big)
+ if (inst.relocs[0].exp.X_op != O_constant
+ && inst.relocs[0].exp.X_op != O_symbol
+ && inst.relocs[0].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)
+ if (inst.relocs[0].exp.X_op == O_constant
+ || inst.relocs[0].exp.X_op == O_big)
{
#if defined BFD_HOST_64_BIT
bfd_int64_t v;
#else
offsetT v;
#endif
- if (inst.reloc.exp.X_op == O_big)
+ if (inst.relocs[0].exp.X_op == O_big)
{
LITTLENUM_TYPE w[X_PRECISION];
LITTLENUM_TYPE * l;
- if (inst.reloc.exp.X_add_number == -1)
+ if (inst.relocs[0].exp.X_add_number == -1)
{
gen_to_words (w, X_PRECISION, E_PRECISION);
l = w;
#endif
}
else
- v = inst.reloc.exp.X_add_number;
+ v = inst.relocs[0].exp.X_add_number;
if (!inst.operands[i].issingle)
{
unsigned immlo = inst.operands[1].imm;
unsigned immhi = inst.operands[1].regisimm
? inst.operands[1].reg
- : inst.reloc.exp.X_unsigned
+ : inst.relocs[0].exp.X_unsigned
? 0
: ((bfd_int64_t)((int) immlo)) >> 32;
int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
inst.operands[1].reg = REG_PC;
inst.operands[1].isreg = 1;
inst.operands[1].preind = 1;
- inst.reloc.pc_rel = 1;
- inst.reloc.type = (thumb_p
+ inst.relocs[0].pc_rel = 1;
+ inst.relocs[0].type = (thumb_p
? BFD_RELOC_ARM_THUMB_OFFSET
: (mode_3
? BFD_RELOC_ARM_HWLITERAL
}
if (reloc_override)
- inst.reloc.type = (bfd_reloc_code_real_type) reloc_override;
- else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC
- || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2)
- && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0)
+ inst.relocs[0].type = (bfd_reloc_code_real_type) reloc_override;
+ else if ((inst.relocs[0].type < BFD_RELOC_ARM_ALU_PC_G0_NC
+ || inst.relocs[0].type > BFD_RELOC_ARM_LDC_SB_G2)
+ && inst.relocs[0].type != BFD_RELOC_ARM_LDR_PC_G0)
{
if (thumb_mode)
- inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
else
- inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_CP_OFF_IMM;
}
/* Prefer + for zero encoded value. */
do_rm_rd_rn (void)
{
constraint ((inst.operands[2].reg == REG_PC), BAD_PC);
- constraint (((inst.reloc.exp.X_op != O_constant
- && inst.reloc.exp.X_op != O_illegal)
- || inst.reloc.exp.X_add_number != 0),
+ constraint (((inst.relocs[0].exp.X_op != O_constant
+ && inst.relocs[0].exp.X_op != O_illegal)
+ || inst.relocs[0].exp.X_add_number != 0),
BAD_ADDR_MODE);
inst.instruction |= inst.operands[0].reg;
inst.instruction |= inst.operands[1].reg << 12;
/* Frag hacking will turn this into a sub instruction if the offset turns
out to be negative. */
- inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
- inst.reloc.pc_rel = 1;
- inst.reloc.exp.X_add_number -= 8;
+ inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE;
+ inst.relocs[0].pc_rel = 1;
+ inst.relocs[0].exp.X_add_number -= 8;
- if (inst.reloc.exp.X_op == O_symbol
- && inst.reloc.exp.X_add_symbol != NULL
- && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
- && THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
- inst.reloc.exp.X_add_number += 1;
+ if (support_interwork
+ && inst.relocs[0].exp.X_op == O_symbol
+ && inst.relocs[0].exp.X_add_symbol != NULL
+ && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
+ && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
+ inst.relocs[0].exp.X_add_number |= 1;
}
/* This is a pseudo-op of the form "adrl rd, label" to be converted
/* Frag hacking will turn this into a sub instruction if the offset turns
out to be negative. */
- inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
- inst.reloc.pc_rel = 1;
+ inst.relocs[0].type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
+ inst.relocs[0].pc_rel = 1;
inst.size = INSN_SIZE * 2;
- inst.reloc.exp.X_add_number -= 8;
+ inst.relocs[0].exp.X_add_number -= 8;
- if (inst.reloc.exp.X_op == O_symbol
- && inst.reloc.exp.X_add_symbol != NULL
- && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
- && THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
- inst.reloc.exp.X_add_number += 1;
+ if (support_interwork
+ && inst.relocs[0].exp.X_op == O_symbol
+ && inst.relocs[0].exp.X_add_symbol != NULL
+ && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
+ && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
+ inst.relocs[0].exp.X_add_number |= 1;
}
static void
do_arit (void)
{
- constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
- && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+ constraint (inst.relocs[0].type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ && inst.relocs[0].type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
THUMB1_RELOC_ONLY);
if (!inst.operands[1].present)
inst.operands[1].reg = inst.operands[0].reg;
constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32
&& inst.operands[0].imm != BFD_RELOC_ARM_TLS_CALL,
_("the only valid suffixes here are '(plt)' and '(tlscall)'"));
- inst.reloc.type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32
+ inst.relocs[0].type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32
? BFD_RELOC_ARM_PLT32
: thumb_mode ? BFD_RELOC_ARM_THM_TLS_CALL : BFD_RELOC_ARM_TLS_CALL;
}
else
- inst.reloc.type = (bfd_reloc_code_real_type) default_reloc;
- inst.reloc.pc_rel = 1;
+ inst.relocs[0].type = (bfd_reloc_code_real_type) default_reloc;
+ inst.relocs[0].pc_rel = 1;
}
static void
/* 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))
+ if (!ARM_FEATURE_ZERO (selected_object_arch)
+ && !ARM_CPU_HAS_FEATURE (selected_object_arch, arm_ext_v5))
want_reloc = TRUE;
#ifdef OBJ_ELF
want_reloc = FALSE;
if (want_reloc)
- inst.reloc.type = BFD_RELOC_ARM_V4BX;
+ inst.relocs[0].type = BFD_RELOC_ARM_V4BX;
}
|| (inst.operands[1].reg == REG_PC),
BAD_ADDR_MODE);
- constraint (inst.reloc.exp.X_op != O_constant
- || inst.reloc.exp.X_add_number != 0,
+ constraint (inst.relocs[0].exp.X_op != O_constant
+ || inst.relocs[0].exp.X_add_number != 0,
_("offset must be zero in ARM encoding"));
constraint ((inst.operands[1].reg == REG_PC), BAD_PC);
inst.instruction |= inst.operands[0].reg << 12;
inst.instruction |= inst.operands[1].reg << 16;
- inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
}
static void
constraint (!(inst.operands[1].immisreg)
&& (inst.operands[0].reg == REG_PC
&& inst.operands[1].reg == REG_PC
- && (inst.reloc.exp.X_add_number & 0x3)),
+ && (inst.relocs[0].exp.X_add_number & 0x3)),
_("ldr to register 15 must be 4-byte aligned"));
}
reject [Rn,...]. */
if (inst.operands[1].preind)
{
- constraint (inst.reloc.exp.X_op != O_constant
- || inst.reloc.exp.X_add_number != 0,
+ constraint (inst.relocs[0].exp.X_op != O_constant
+ || inst.relocs[0].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.relocs[0].exp.X_op != O_constant
+ || inst.relocs[0].exp.X_add_number != 0,
_("this instruction requires a post-indexed address"));
inst.operands[1].preind = 0;
static void
do_mov (void)
{
- constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
- && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+ constraint (inst.relocs[0].type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ && inst.relocs[0].type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
THUMB1_RELOC_ONLY);
inst.instruction |= inst.operands[0].reg << 12;
encode_arm_shifter_operand (1);
bfd_boolean top;
top = (inst.instruction & 0x00400000) != 0;
- constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
+ constraint (top && inst.relocs[0].type == BFD_RELOC_ARM_MOVW,
_(":lower16: not allowed in this instruction"));
- constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
+ constraint (!top && inst.relocs[0].type == BFD_RELOC_ARM_MOVT,
_(":upper16: not allowed in this instruction"));
inst.instruction |= inst.operands[0].reg << 12;
- if (inst.reloc.type == BFD_RELOC_UNUSED)
+ if (inst.relocs[0].type == BFD_RELOC_UNUSED)
{
- imm = inst.reloc.exp.X_add_number;
+ imm = inst.relocs[0].exp.X_add_number;
/* The value is in two pieces: 0:11, 16:19. */
inst.instruction |= (imm & 0x00000fff);
inst.instruction |= (imm & 0x0000f000) << 4;
else
{
inst.instruction |= INST_IMMEDIATE;
- inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
- inst.reloc.pc_rel = 0;
+ inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE;
+ inst.relocs[0].pc_rel = 0;
}
}
_("extraneous shift as part of operand to shift insn"));
}
else
- inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM;
}
static void
do_smc (void)
{
- inst.reloc.type = BFD_RELOC_ARM_SMC;
- inst.reloc.pc_rel = 0;
+ inst.relocs[0].type = BFD_RELOC_ARM_SMC;
+ inst.relocs[0].pc_rel = 0;
}
static void
do_hvc (void)
{
- inst.reloc.type = BFD_RELOC_ARM_HVC;
- inst.reloc.pc_rel = 0;
+ inst.relocs[0].type = BFD_RELOC_ARM_HVC;
+ inst.relocs[0].pc_rel = 0;
}
static void
do_swi (void)
{
- inst.reloc.type = BFD_RELOC_ARM_SWI;
- inst.reloc.pc_rel = 0;
+ inst.relocs[0].type = BFD_RELOC_ARM_SWI;
+ inst.relocs[0].pc_rel = 0;
}
static void
constraint (inst.operands[0].reg == inst.operands[1].reg
|| inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
- constraint (inst.reloc.exp.X_op != O_constant
- || inst.reloc.exp.X_add_number != 0,
+ constraint (inst.relocs[0].exp.X_op != O_constant
+ || inst.relocs[0].exp.X_add_number != 0,
_("offset must be zero in ARM encoding"));
inst.instruction |= inst.operands[0].reg << 12;
inst.instruction |= inst.operands[1].reg;
inst.instruction |= inst.operands[2].reg << 16;
- inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
}
static void
[Rn]{!}. The instruction does not really support stacking or
unstacking, so we have to emulate these by setting appropriate
bits and offsets. */
- constraint (inst.reloc.exp.X_op != O_constant
- || inst.reloc.exp.X_add_number != 0,
+ constraint (inst.relocs[0].exp.X_op != O_constant
+ || inst.relocs[0].exp.X_add_number != 0,
_("this instruction does not support indexing"));
if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback)
- inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
+ inst.relocs[0].exp.X_add_number = 12 * inst.operands[1].imm;
if (!(inst.instruction & INDEX_UP))
- inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
+ inst.relocs[0].exp.X_add_number = -inst.relocs[0].exp.X_add_number;
if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback)
{
if (inst.operands[1].writeback)
inst.instruction |= WRITE_BACK;
inst.instruction |= inst.operands[1].reg << 16;
- inst.instruction |= inst.reloc.exp.X_add_number << 4;
+ inst.instruction |= inst.relocs[0].exp.X_add_number << 4;
inst.instruction |= inst.operands[1].imm;
}
else
static void
encode_thumb32_shifted_operand (int i)
{
- unsigned int value = inst.reloc.exp.X_add_number;
+ unsigned int value = inst.relocs[0].exp.X_add_number;
unsigned int shift = inst.operands[i].shift_kind;
constraint (inst.operands[i].immisreg,
inst.instruction |= SHIFT_ROR << 4;
else
{
- constraint (inst.reloc.exp.X_op != O_constant,
+ constraint (inst.relocs[0].exp.X_op != O_constant,
_("expression too complex"));
constraint (value > 32
inst.instruction |= inst.operands[i].imm;
if (inst.operands[i].shifted)
{
- constraint (inst.reloc.exp.X_op != O_constant,
+ constraint (inst.relocs[0].exp.X_op != O_constant,
_("expression too complex"));
- constraint (inst.reloc.exp.X_add_number < 0
- || inst.reloc.exp.X_add_number > 3,
+ constraint (inst.relocs[0].exp.X_add_number < 0
+ || inst.relocs[0].exp.X_add_number > 3,
_("shift out of range"));
- inst.instruction |= inst.reloc.exp.X_add_number << 4;
+ inst.instruction |= inst.relocs[0].exp.X_add_number << 4;
}
- inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
}
else if (inst.operands[i].preind)
{
if (inst.operands[i].writeback)
inst.instruction |= 0x00000100;
}
- inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_IMM;
}
else if (inst.operands[i].postind)
{
inst.instruction |= 0x00200000;
else
inst.instruction |= 0x00000900;
- inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_IMM;
}
else /* unindexed - only for coprocessor */
inst.error = _("instruction does not accept unindexed addressing");
X(_asrs, 1000, fa50f000), \
X(_b, e000, f000b000), \
X(_bcond, d000, f0008000), \
+ X(_bf, 0000, f040e001), \
+ X(_bfcsel,0000, f000e001), \
+ X(_bfx, 0000, f060e001), \
+ X(_bfl, 0000, f000c001), \
+ X(_bflx, 0000, f070e001), \
X(_bic, 4380, ea200000), \
X(_bics, 4380, ea300000), \
X(_cmn, 42c0, eb100f00), \
X(_cpsid, b670, f3af8600), \
X(_cpy, 4600, ea4f0000), \
X(_dec_sp,80dd, f1ad0d00), \
+ X(_dls, 0000, f040e001), \
X(_eor, 4040, ea800000), \
X(_eors, 4040, ea900000), \
X(_inc_sp,00dd, f10d0d00), \
X(_ldr_pc,4800, f85f0000), \
X(_ldr_pc2,4800, f85f0000), \
X(_ldr_sp,9800, f85d0000), \
+ X(_le, 0000, f00fc001), \
X(_lsl, 0000, fa00f000), \
X(_lsls, 0000, fa10f000), \
X(_lsr, 0800, fa20f000), \
X(_yield, bf10, f3af8001), \
X(_wfe, bf20, f3af8002), \
X(_wfi, bf30, f3af8003), \
+ X(_wls, 0000, f040c001), \
X(_sev, bf40, f3af8004), \
X(_sevl, bf50, f3af8005), \
X(_udf, de00, f7f0a000)
reject_bad_reg (Rd);
inst.instruction |= (Rn << 16) | (Rd << 8);
- inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMM12;
}
/* Parse an add or subtract instruction. We get here with inst.instruction
{
inst.instruction = THUMB_OP16(opcode);
inst.instruction |= (Rd << 4) | Rs;
- if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
- || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+ if (inst.relocs[0].type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ || (inst.relocs[0].type
+ > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC))
{
if (inst.size_req == 2)
- inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD;
else
inst.relax = opcode;
}
if (inst.size_req == 4
|| (inst.size_req != 2 && !opcode))
{
- constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
- && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+ constraint ((inst.relocs[0].type
+ >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC)
+ && (inst.relocs[0].type
+ <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC) ,
THUMB1_RELOC_ONLY);
if (Rd == REG_PC)
{
constraint (add, BAD_PC);
constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs,
_("only SUBS PC, LR, #const allowed"));
- constraint (inst.reloc.exp.X_op != O_constant,
+ constraint (inst.relocs[0].exp.X_op != O_constant,
_("expression too complex"));
- constraint (inst.reloc.exp.X_add_number < 0
- || inst.reloc.exp.X_add_number > 0xff,
+ constraint (inst.relocs[0].exp.X_add_number < 0
+ || inst.relocs[0].exp.X_add_number > 0xff,
_("immediate value out of range"));
inst.instruction = T2_SUBS_PC_LR
- | inst.reloc.exp.X_add_number;
- inst.reloc.type = BFD_RELOC_UNUSED;
+ | inst.relocs[0].exp.X_add_number;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
return;
}
else if (Rs == REG_PC)
{
/* Always use addw/subw. */
inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
- inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMM12;
}
else
{
inst.instruction = (inst.instruction & 0xe1ffffff)
| 0x10000000;
if (flags)
- inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
else
- inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_ADD_IMM;
}
inst.instruction |= Rd << 8;
inst.instruction |= Rs << 16;
}
else
{
- unsigned int value = inst.reloc.exp.X_add_number;
+ unsigned int value = inst.relocs[0].exp.X_add_number;
unsigned int shift = inst.operands[2].shift_kind;
Rn = inst.operands[2].reg;
inst.instruction = (inst.instruction == T_MNEM_add
? 0x0000 : 0x8000);
inst.instruction |= (Rd << 4) | Rs;
- inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD;
return;
}
/* Generate a 32-bit opcode. */
inst.instruction = THUMB_OP32 (inst.instruction);
inst.instruction |= Rd << 8;
- inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
- inst.reloc.pc_rel = 1;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_ADD_PC12;
+ inst.relocs[0].pc_rel = 1;
}
else
{
/* Generate a 16-bit opcode. */
inst.instruction = THUMB_OP16 (inst.instruction);
- inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
- inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */
- inst.reloc.pc_rel = 1;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD;
+ inst.relocs[0].exp.X_add_number -= 4; /* PC relative adjust. */
+ inst.relocs[0].pc_rel = 1;
inst.instruction |= Rd << 4;
}
- if (inst.reloc.exp.X_op == O_symbol
- && inst.reloc.exp.X_add_symbol != NULL
- && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
- && THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
- inst.reloc.exp.X_add_number += 1;
+ if (inst.relocs[0].exp.X_op == O_symbol
+ && inst.relocs[0].exp.X_add_symbol != NULL
+ && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
+ && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
+ inst.relocs[0].exp.X_add_number += 1;
}
/* Arithmetic instructions for which there is just one 16-bit
inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
inst.instruction |= Rd << 8;
inst.instruction |= Rs << 16;
- inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
}
else
{
inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
inst.instruction |= Rd << 8;
inst.instruction |= Rs << 16;
- inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
}
else
{
&& (inst.size_req == 4
|| (inst.size_req != 2
&& (inst.operands[0].hasreloc
- || inst.reloc.exp.X_op == O_constant))))
+ || inst.relocs[0].exp.X_op == O_constant))))
{
inst.instruction = THUMB_OP32(opcode);
if (cond == COND_ALWAYS)
if (unified_syntax && inst.size_req != 2)
inst.relax = opcode;
}
- inst.reloc.type = reloc;
- inst.reloc.pc_rel = 1;
+ inst.relocs[0].type = reloc;
+ inst.relocs[0].pc_rel = 1;
}
/* Actually do the work for Thumb state bkpt and hlt. The only difference
the branch encoding is now needed to deal with TLSCALL relocs.
So if we see a PLT reloc now, put it back to how it used to be to
keep the preexisting behaviour. */
- if (inst.reloc.type == BFD_RELOC_ARM_PLT32)
- inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
+ if (inst.relocs[0].type == BFD_RELOC_ARM_PLT32)
+ inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH23;
#if defined(OBJ_COFF)
/* If the destination of the branch is a defined symbol which does not have
the THUMB_FUNC attribute, then we must be calling a function which has
the (interfacearm) attribute. We look for the Thumb entry point to that
function and change the branch to refer to that function instead. */
- if ( inst.reloc.exp.X_op == O_symbol
- && inst.reloc.exp.X_add_symbol != NULL
- && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
- && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
- inst.reloc.exp.X_add_symbol =
- find_real_start (inst.reloc.exp.X_add_symbol);
+ if ( inst.relocs[0].exp.X_op == O_symbol
+ && inst.relocs[0].exp.X_add_symbol != NULL
+ && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
+ && ! THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
+ inst.relocs[0].exp.X_add_symbol
+ = find_real_start (inst.relocs[0].exp.X_add_symbol);
#endif
}
set_it_insn_type (OUTSIDE_IT_INSN);
constraint (inst.operands[0].reg > 7, BAD_HIREG);
inst.instruction |= inst.operands[0].reg;
- inst.reloc.pc_rel = 1;
- inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
+ inst.relocs[0].pc_rel = 1;
+ inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH7;
}
static void
/* Helper function used for both push/pop and ldm/stm. */
static void
-encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
+encode_thumb2_multi (bfd_boolean do_io, int base, unsigned mask,
+ bfd_boolean writeback)
{
- bfd_boolean load;
+ bfd_boolean load, store;
- load = (inst.instruction & (1 << 20)) != 0;
+ gas_assert (base != -1 || !do_io);
+ load = do_io && ((inst.instruction & (1 << 20)) != 0);
+ store = do_io && !load;
if (mask & (1 << 13))
inst.error = _("SP not allowed in register list");
- if ((mask & (1 << base)) != 0
+ if (do_io && (mask & (1 << base)) != 0
&& writeback)
inst.error = _("having the base register in the register list when "
"using write back is UNPREDICTABLE");
set_it_insn_type_last ();
}
}
- else
+ else if (store)
{
if (mask & (1 << 15))
inst.error = _("PC not allowed in register list");
}
- if ((mask & (mask - 1)) == 0)
+ if (do_io && ((mask & (mask - 1)) == 0))
{
/* Single register transfers implemented as str/ldr. */
if (writeback)
inst.instruction |= WRITE_BACK;
inst.instruction |= mask;
- inst.instruction |= base << 16;
+ if (do_io)
+ inst.instruction |= base << 16;
}
static void
do_t_ldmstm (void)
{
/* This really doesn't seem worth it. */
- constraint (inst.reloc.type != BFD_RELOC_UNUSED,
+ constraint (inst.relocs[0].type != BFD_RELOC_UNUSED,
_("expression too complex"));
constraint (inst.operands[1].writeback,
_("Thumb load/store multiple does not support {reglist}^"));
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_multi (TRUE /* do_io */, inst.operands[0].reg,
+ inst.operands[1].imm,
+ inst.operands[0].writeback);
}
}
else
inst.instruction |= inst.operands[0].reg << 12;
inst.instruction |= inst.operands[1].reg << 16;
- inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_U8;
}
static void
{
if (Rn == REG_PC)
{
- if (inst.reloc.pc_rel)
+ if (inst.relocs[0].pc_rel)
opcode = T_MNEM_ldr_pc2;
else
opcode = T_MNEM_ldr_pc;
}
inst.instruction |= THUMB_OP16 (opcode);
if (inst.size_req == 2)
- inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET;
else
inst.relax = opcode;
return;
inst.instruction = T_OPCODE_STR_SP;
inst.instruction |= inst.operands[0].reg << 8;
- inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET;
return;
}
/* Immediate offset. */
inst.instruction |= inst.operands[0].reg;
inst.instruction |= inst.operands[1].reg << 3;
- inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET;
return;
}
{
inst.instruction = THUMB_OP16 (opcode);
inst.instruction |= Rn << 8;
- if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
- || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+ if (inst.relocs[0].type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ || inst.relocs[0].type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
{
if (inst.size_req == 2)
- inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_IMM;
else
inst.relax = opcode;
}
}
else
{
- constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
- && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+ constraint ((inst.relocs[0].type
+ >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC)
+ && (inst.relocs[0].type
+ <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC) ,
THUMB1_RELOC_ONLY);
inst.instruction = THUMB_OP32 (inst.instruction);
inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
inst.instruction |= Rn << r0off;
- inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
}
}
else if (inst.operands[1].shifted && inst.operands[1].immisreg
{
inst.instruction |= Rn;
inst.instruction |= Rm << 3;
- inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT;
}
else
{
constraint (Rn > 7,
_("only lo regs allowed with immediate"));
inst.instruction |= Rn << 8;
- inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_IMM;
}
}
bfd_boolean top;
top = (inst.instruction & 0x00800000) != 0;
- if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
+ if (inst.relocs[0].type == BFD_RELOC_ARM_MOVW)
{
constraint (top, _(":lower16: not allowed in this instruction"));
- inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_MOVW;
}
- else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
+ else if (inst.relocs[0].type == BFD_RELOC_ARM_MOVT)
{
constraint (!top, _(":upper16: not allowed in this instruction"));
- inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_MOVT;
}
Rd = inst.operands[0].reg;
reject_bad_reg (Rd);
inst.instruction |= Rd << 8;
- if (inst.reloc.type == BFD_RELOC_UNUSED)
+ if (inst.relocs[0].type == BFD_RELOC_UNUSED)
{
- imm = inst.reloc.exp.X_add_number;
+ imm = inst.relocs[0].exp.X_add_number;
inst.instruction |= (imm & 0xf000) << 4;
inst.instruction |= (imm & 0x0800) << 15;
inst.instruction |= (imm & 0x0700) << 4;
inst.instruction = THUMB_OP32 (inst.instruction);
inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
inst.instruction |= Rn << r0off;
- inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
}
else
{
if (!inst.operands[2].isreg)
{
inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
- inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
}
else
{
inst.instruction |= Rm;
if (inst.operands[3].present)
{
- unsigned int val = inst.reloc.exp.X_add_number;
- constraint (inst.reloc.exp.X_op != O_constant,
+ unsigned int val = inst.relocs[0].exp.X_add_number;
+ constraint (inst.relocs[0].exp.X_op != O_constant,
_("expression too complex"));
inst.instruction |= (val & 0x1c) << 10;
inst.instruction |= (val & 0x03) << 6;
constraint (inst.operands[0].writeback,
_("push/pop do not support {reglist}^"));
- constraint (inst.reloc.type != BFD_RELOC_UNUSED,
+ constraint (inst.relocs[0].type != BFD_RELOC_UNUSED,
_("expression too complex"));
mask = inst.operands[0].imm;
else if (unified_syntax)
{
inst.instruction = THUMB_OP32 (inst.instruction);
- encode_thumb2_ldmstm (13, mask, TRUE);
+ encode_thumb2_multi (TRUE /* do_io */, 13, mask, TRUE);
+ }
+ else
+ {
+ inst.error = _("invalid register list to push/pop instruction");
+ return;
}
+}
+
+static void
+do_t_clrm (void)
+{
+ if (unified_syntax)
+ encode_thumb2_multi (FALSE /* do_io */, -1, inst.operands[0].imm, FALSE);
else
{
inst.error = _("invalid register list to push/pop instruction");
}
}
+static void
+do_t_vscclrm (void)
+{
+ if (inst.operands[0].issingle)
+ {
+ inst.instruction |= (inst.operands[0].reg & 0x1) << 22;
+ inst.instruction |= (inst.operands[0].reg & 0x1e) << 11;
+ inst.instruction |= inst.operands[0].imm;
+ }
+ else
+ {
+ inst.instruction |= (inst.operands[0].reg & 0x10) << 18;
+ inst.instruction |= (inst.operands[0].reg & 0xf) << 12;
+ inst.instruction |= 1 << 8;
+ inst.instruction |= inst.operands[0].imm << 1;
+ }
+}
+
static void
do_t_rbit (void)
{
if (inst.size_req == 4 || !unified_syntax)
narrow = FALSE;
- if (inst.reloc.exp.X_op != O_constant
- || inst.reloc.exp.X_add_number != 0)
+ if (inst.relocs[0].exp.X_op != O_constant
+ || inst.relocs[0].exp.X_add_number != 0)
narrow = FALSE;
/* Turn rsb #0 into 16-bit neg. We should probably do this via
relaxation, but it doesn't seem worth the hassle. */
if (narrow)
{
- inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
inst.instruction = THUMB_OP16 (T_MNEM_negs);
inst.instruction |= Rs << 3;
inst.instruction |= Rd;
else
{
inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
- inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE;
}
}
else
inst.instruction |= inst.operands[0].reg << 8;
encode_thumb32_shifted_operand (1);
/* Prevent the incorrect generation of an ARM_IMMEDIATE fixup. */
- inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
}
}
else
case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
default: abort ();
}
- inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT;
inst.instruction |= inst.operands[0].reg;
inst.instruction |= inst.operands[1].reg << 3;
}
case T_MNEM_ror: inst.error = _("ror #imm not supported"); return;
default: abort ();
}
- inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT;
inst.instruction |= inst.operands[0].reg;
inst.instruction |= inst.operands[1].reg << 3;
}
static void
do_t_smc (void)
{
- unsigned int value = inst.reloc.exp.X_add_number;
+ unsigned int value = inst.relocs[0].exp.X_add_number;
constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7a),
_("SMC is not permitted on this architecture"));
- constraint (inst.reloc.exp.X_op != O_constant,
+ constraint (inst.relocs[0].exp.X_op != O_constant,
_("expression too complex"));
- inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
inst.instruction |= (value & 0xf000) >> 12;
inst.instruction |= (value & 0x0ff0);
inst.instruction |= (value & 0x000f) << 16;
static void
do_t_hvc (void)
{
- unsigned int value = inst.reloc.exp.X_add_number;
+ unsigned int value = inst.relocs[0].exp.X_add_number;
- inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
inst.instruction |= (value & 0x0fff);
inst.instruction |= (value & 0xf000) << 4;
}
if (inst.operands[3].present)
{
- offsetT shift_amount = inst.reloc.exp.X_add_number;
+ offsetT shift_amount = inst.relocs[0].exp.X_add_number;
- inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.relocs[0].type = BFD_RELOC_UNUSED;
- constraint (inst.reloc.exp.X_op != O_constant,
+ constraint (inst.relocs[0].exp.X_op != O_constant,
_("expression too complex"));
if (shift_amount != 0)
inst.instruction |= inst.operands[0].reg << 8;
inst.instruction |= inst.operands[1].reg << 12;
inst.instruction |= inst.operands[2].reg << 16;
- inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
+ inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_U8;
}
static void
static void
do_t_swi (void)
{
- inst.reloc.type = BFD_RELOC_ARM_SWI;
+ inst.relocs[0].type = BFD_RELOC_ARM_SWI;
}
static void
inst.instruction |= Rn << 16;
}
+/* Checking the range of the branch offset (VAL) with NBITS bits
+ and IS_SIGNED signedness. Also checks the LSB to be 0. */
+static int
+v8_1_branch_value_check (int val, int nbits, int is_signed)
+{
+ gas_assert (nbits > 0 && nbits <= 32);
+ if (is_signed)
+ {
+ int cmp = (1 << (nbits - 1));
+ if ((val < -cmp) || (val >= cmp) || (val & 0x01))
+ return FAIL;
+ }
+ else
+ {
+ if ((val <= 0) || (val >= (1 << nbits)) || (val & 0x1))
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/* For branches in Armv8.1-M Mainline. */
+static void
+do_t_branch_future (void)
+{
+ unsigned long insn = inst.instruction;
+
+ inst.instruction = THUMB_OP32 (inst.instruction);
+ if (inst.operands[0].hasreloc == 0)
+ {
+ if (v8_1_branch_value_check (inst.operands[0].imm, 5, FALSE) == FAIL)
+ as_bad (BAD_BRANCH_OFF);
+
+ inst.instruction |= ((inst.operands[0].imm & 0x1f) >> 1) << 23;
+ }
+ else
+ {
+ inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH5;
+ inst.relocs[0].pc_rel = 1;
+ }
+
+ switch (insn)
+ {
+ case T_MNEM_bf:
+ if (inst.operands[1].hasreloc == 0)
+ {
+ int val = inst.operands[1].imm;
+ if (v8_1_branch_value_check (inst.operands[1].imm, 17, TRUE) == FAIL)
+ as_bad (BAD_BRANCH_OFF);
+
+ int immA = (val & 0x0001f000) >> 12;
+ int immB = (val & 0x00000ffc) >> 2;
+ int immC = (val & 0x00000002) >> 1;
+ inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+ }
+ else
+ {
+ inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF17;
+ inst.relocs[1].pc_rel = 1;
+ }
+ break;
+
+ case T_MNEM_bfl:
+ if (inst.operands[1].hasreloc == 0)
+ {
+ int val = inst.operands[1].imm;
+ if (v8_1_branch_value_check (inst.operands[1].imm, 19, TRUE) == FAIL)
+ as_bad (BAD_BRANCH_OFF);
+
+ int immA = (val & 0x0007f000) >> 12;
+ int immB = (val & 0x00000ffc) >> 2;
+ int immC = (val & 0x00000002) >> 1;
+ inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+ }
+ else
+ {
+ inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF19;
+ inst.relocs[1].pc_rel = 1;
+ }
+ break;
+
+ case T_MNEM_bfcsel:
+ /* Operand 1. */
+ if (inst.operands[1].hasreloc == 0)
+ {
+ int val = inst.operands[1].imm;
+ int immA = (val & 0x00001000) >> 12;
+ int immB = (val & 0x00000ffc) >> 2;
+ int immC = (val & 0x00000002) >> 1;
+ inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+ }
+ else
+ {
+ inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF13;
+ inst.relocs[1].pc_rel = 1;
+ }
+
+ /* Operand 2. */
+ if (inst.operands[2].hasreloc == 0)
+ {
+ constraint ((inst.operands[0].hasreloc != 0), BAD_ARGS);
+ int val2 = inst.operands[2].imm;
+ int val0 = inst.operands[0].imm & 0x1f;
+ int diff = val2 - val0;
+ if (diff == 4)
+ inst.instruction |= 1 << 17; /* T bit. */
+ else if (diff != 2)
+ as_bad (_("out of range label-relative fixup value"));
+ }
+ else
+ {
+ constraint ((inst.operands[0].hasreloc == 0), BAD_ARGS);
+ inst.relocs[2].type = BFD_RELOC_THUMB_PCREL_BFCSEL;
+ inst.relocs[2].pc_rel = 1;
+ }
+
+ /* Operand 3. */
+ constraint (inst.cond != COND_ALWAYS, BAD_COND);
+ inst.instruction |= (inst.operands[3].imm & 0xf) << 18;
+ break;
+
+ case T_MNEM_bfx:
+ case T_MNEM_bflx:
+ inst.instruction |= inst.operands[1].reg << 16;
+ break;
+
+ default: abort ();
+ }
+}
+
+/* Helper function for do_t_loloop to handle relocations. */
+static void
+v8_1_loop_reloc (int is_le)
+{
+ if (inst.relocs[0].exp.X_op == O_constant)
+ {
+ int value = inst.relocs[0].exp.X_add_number;
+ value = (is_le) ? -value : value;
+
+ if (v8_1_branch_value_check (value, 12, FALSE) == FAIL)
+ as_bad (BAD_BRANCH_OFF);
+
+ int imml, immh;
+
+ immh = (value & 0x00000ffc) >> 2;
+ imml = (value & 0x00000002) >> 1;
+
+ inst.instruction |= (imml << 11) | (immh << 1);
+ }
+ else
+ {
+ inst.relocs[0].type = BFD_RELOC_ARM_THUMB_LOOP12;
+ inst.relocs[0].pc_rel = 1;
+ }
+}
+
+/* To handle the Scalar Low Overhead Loop instructions
+ in Armv8.1-M Mainline. */
+static void
+do_t_loloop (void)
+{
+ unsigned long insn = inst.instruction;
+
+ set_it_insn_type (OUTSIDE_IT_INSN);
+ inst.instruction = THUMB_OP32 (inst.instruction);
+
+ switch (insn)
+ {
+ case T_MNEM_le:
+ /* le <label>. */
+ if (!inst.operands[0].present)
+ inst.instruction |= 1 << 21;
+
+ v8_1_loop_reloc (TRUE);
+ break;
+
+ case T_MNEM_wls:
+ v8_1_loop_reloc (FALSE);
+ /* Fall through. */
+ case T_MNEM_dls:
+ constraint (inst.operands[1].isreg != 1, BAD_ARGS);
+ inst.instruction |= (inst.operands[1].reg << 16);
+ break;
+
+ default: abort();
+ }
+}
+
/* Neon instruction encoder helpers. */
/* Encodings for the different types for various Neon opcodes. */
/* Half-precision conversions for Advanced SIMD -- neon. */
case NS_QD:
case NS_DQ:
+ if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+ return;
if ((rs == NS_DQ)
&& (inst.vectype.el[0].size != 16 || inst.vectype.el[1].size != 32))
case NS_HI:
case NS_FI: /* case 10 (fconsts). */
ldconst = "fconsts";
- encode_fconstd:
+ encode_fconstd:
+ if (!inst.operands[1].immisfloat)
+ {
+ unsigned new_imm;
+ /* Immediate has to fit in 8 bits so float is enough. */
+ float imm = (float) inst.operands[1].imm;
+ memcpy (&new_imm, &imm, sizeof (float));
+ /* But the assembly may have been written to provide an integer
+ bit pattern that equates to a float, so check that the
+ conversion has worked. */
+ if (is_quarter_float (new_imm))
+ {
+ if (is_quarter_float (inst.operands[1].imm))
+ as_warn (_("immediate constant is valid both as a bit-pattern and a floating point value (using the fp value)"));
+
+ inst.operands[1].imm = new_imm;
+ inst.operands[1].immisfloat = 1;
+ }
+ }
+
if (is_quarter_float (inst.operands[1].imm))
{
inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
enum neon_shape rs = neon_select_shape (NS_HH, NS_NULL);
constraint (rs != NS_HH, _("invalid suffix"));
- constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
- _(BAD_FPU));
+ if (inst.cond != COND_ALWAYS)
+ {
+ if (thumb_mode)
+ {
+ as_warn (_("ARMv8.2 scalar fp16 instruction cannot be conditional,"
+ " the behaviour is UNPREDICTABLE"));
+ }
+ else
+ {
+ inst.error = BAD_COND;
+ return;
+ }
+ }
do_vfp_sp_monadic ();
}
}
+static void
+do_t_vldr_vstr_sysreg (void)
+{
+ int fp_vldr_bitno = 20, sysreg_vldr_bitno = 20;
+ bfd_boolean is_vldr = ((inst.instruction & (1 << fp_vldr_bitno)) != 0);
+
+ /* Use of PC is UNPREDICTABLE. */
+ if (inst.operands[1].reg == REG_PC)
+ inst.error = _("Use of PC here is UNPREDICTABLE");
+
+ if (inst.operands[1].immisreg)
+ inst.error = _("instruction does not accept register index");
+
+ if (!inst.operands[1].isreg)
+ inst.error = _("instruction does not accept PC-relative addressing");
+
+ if (abs (inst.operands[1].imm) >= (1 << 7))
+ inst.error = _("immediate value out of range");
+
+ inst.instruction = 0xec000f80;
+ if (is_vldr)
+ inst.instruction |= 1 << sysreg_vldr_bitno;
+ encode_arm_cp_address (1, TRUE, FALSE, BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM);
+ inst.instruction |= (inst.operands[0].imm & 0x7) << 13;
+ inst.instruction |= (inst.operands[0].imm & 0x8) << 19;
+}
+
+static void
+do_vldr_vstr (void)
+{
+ bfd_boolean sysreg_op = !inst.operands[0].isreg;
+
+ /* VLDR/VSTR (System Register). */
+ if (sysreg_op)
+ {
+ if (!mark_feature_used (&arm_ext_v8_1m_main))
+ as_bad (_("Instruction not permitted on this architecture"));
+
+ do_t_vldr_vstr_sysreg ();
+ }
+ /* VLDR/VSTR. */
+ else
+ {
+ if (!mark_feature_used (&fpu_vfp_ext_v1xd))
+ as_bad (_("Instruction not permitted on this architecture"));
+ do_neon_ldr_str ();
+ }
+}
+
/* "interleave" version also handles non-interleaving register VLD1/VST1
instructions. */
else
{
constraint (inst.operands[1].immisreg, BAD_ADDR_MODE);
- constraint (inst.reloc.exp.X_op != O_constant
- || inst.reloc.exp.X_add_number != 0,
+ constraint (inst.relocs[0].exp.X_op != O_constant
+ || inst.relocs[0].exp.X_add_number != 0,
BAD_ADDR_MODE);
if (inst.operands[1].writeback)
{
constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_armv8),
_(BAD_FPU));
- constraint (inst.reloc.exp.X_op != O_constant, _("expression too complex"));
- unsigned rot = inst.reloc.exp.X_add_number;
+ constraint (inst.relocs[0].exp.X_op != O_constant,
+ _("expression too complex"));
+ unsigned rot = inst.relocs[0].exp.X_add_number;
constraint (rot != 0 && rot != 90 && rot != 180 && rot != 270,
_("immediate out of range"));
rot /= 90;
{
constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_armv8),
_(BAD_FPU));
- constraint (inst.reloc.exp.X_op != O_constant, _("expression too complex"));
- unsigned rot = inst.reloc.exp.X_add_number;
+ constraint (inst.relocs[0].exp.X_op != O_constant,
+ _("expression too complex"));
+ unsigned rot = inst.relocs[0].exp.X_add_number;
constraint (rot != 90 && rot != 270, _("immediate out of range"));
enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
unsigned size = neon_check_type (3, rs, N_EQK, N_EQK,
start of the instruction. */
dwarf2_emit_insn (0);
- switch (inst.reloc.exp.X_op)
+ switch (inst.relocs[0].exp.X_op)
{
case O_symbol:
- sym = inst.reloc.exp.X_add_symbol;
- offset = inst.reloc.exp.X_add_number;
+ sym = inst.relocs[0].exp.X_add_symbol;
+ offset = inst.relocs[0].exp.X_add_number;
break;
case O_constant:
sym = NULL;
- offset = inst.reloc.exp.X_add_number;
+ offset = inst.relocs[0].exp.X_add_number;
break;
default:
- sym = make_expr_symbol (&inst.reloc.exp);
+ sym = make_expr_symbol (&inst.relocs[0].exp);
offset = 0;
break;
}
else
md_number_to_chars (to, inst.instruction, inst.size);
- if (inst.reloc.type != BFD_RELOC_UNUSED)
- fix_new_arm (frag_now, to - frag_now->fr_literal,
- inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
- inst.reloc.type);
+ int r;
+ for (r = 0; r < ARM_IT_MAX_RELOCS; r++)
+ {
+ if (inst.relocs[r].type != BFD_RELOC_UNUSED)
+ fix_new_arm (frag_now, to - frag_now->fr_literal,
+ inst.size, & inst.relocs[r].exp, inst.relocs[r].pc_rel,
+ inst.relocs[r].type);
+ }
dwarf2_emit_insn (inst.size);
}
}
memset (&inst, '\0', sizeof (inst));
- inst.reloc.type = BFD_RELOC_UNUSED;
+ int r;
+ for (r = 0; r < ARM_IT_MAX_RELOCS; r++)
+ inst.relocs[r].type = BFD_RELOC_UNUSED;
opcode = opcode_lookup (&p);
if (!opcode)
{ "tlscall", BFD_RELOC_ARM_TLS_CALL},
{ "TLSCALL", BFD_RELOC_ARM_TLS_CALL},
{ "tlsdescseq", BFD_RELOC_ARM_TLS_DESCSEQ},
- { "TLSDESCSEQ", BFD_RELOC_ARM_TLS_DESCSEQ}
+ { "TLSDESCSEQ", BFD_RELOC_ARM_TLS_DESCSEQ},
+ { "gotfuncdesc", BFD_RELOC_ARM_GOTFUNCDESC },
+ { "GOTFUNCDESC", BFD_RELOC_ARM_GOTFUNCDESC },
+ { "gotofffuncdesc", BFD_RELOC_ARM_GOTOFFFUNCDESC },
+ { "GOTOFFFUNCDESC", BFD_RELOC_ARM_GOTOFFFUNCDESC },
+ { "funcdesc", BFD_RELOC_ARM_FUNCDESC },
+ { "FUNCDESC", BFD_RELOC_ARM_FUNCDESC },
+ { "tlsgd_fdpic", BFD_RELOC_ARM_TLS_GD32_FDPIC }, { "TLSGD_FDPIC", BFD_RELOC_ARM_TLS_GD32_FDPIC },
+ { "tlsldm_fdpic", BFD_RELOC_ARM_TLS_LDM32_FDPIC }, { "TLSLDM_FDPIC", BFD_RELOC_ARM_TLS_LDM32_FDPIC },
+ { "gottpoff_fdpic", BFD_RELOC_ARM_TLS_IE32_FDPIC }, { "GOTTPOFF_FDIC", BFD_RELOC_ARM_TLS_IE32_FDPIC },
};
#endif
#define C3(mnem, op, nops, ops, ae) \
{ #mnem, OPS##nops ops, OT_cinfix3, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
+/* Thumb-only variants of TCE and TUE. */
+#define ToC(mnem, top, nops, ops, te) \
+ { mnem, OPS##nops ops, OT_csuffix, 0x0, 0x##top, 0, THUMB_VARIANT, NULL, \
+ do_##te }
+
+#define ToU(mnem, top, nops, ops, te) \
+ { mnem, OPS##nops ops, OT_unconditional, 0x0, 0x##top, 0, THUMB_VARIANT, \
+ NULL, do_##te }
+
+/* T_MNEM_xyz enumerator variants of ToC. */
+#define toC(mnem, top, nops, ops, te) \
+ { mnem, OPS##nops ops, OT_csuffix, 0x0, T_MNEM##top, 0, THUMB_VARIANT, NULL, \
+ do_##te }
+
+/* T_MNEM_xyz enumerator variants of ToU. */
+#define toU(mnem, top, nops, ops, te) \
+ { mnem, OPS##nops ops, OT_unconditional, 0x0, T_MNEM##top, 0, THUMB_VARIANT, \
+ NULL, do_##te }
+
/* Legacy mnemonics that always have conditional infix after the third
character. */
#define CL(mnem, op, nops, ops, ae) \
TCE("usat16", 6e00f30, f3a00000, 3, (RRnpc, I15, RRnpc), usat16, t_usat16),
#undef ARM_VARIANT
-#define ARM_VARIANT & arm_ext_v6k
+#define ARM_VARIANT & arm_ext_v6k_v6t2
#undef THUMB_VARIANT
-#define THUMB_VARIANT & arm_ext_v6k
+#define THUMB_VARIANT & arm_ext_v6k_v6t2
tCE("yield", 320f001, _yield, 0, (), noargs, t_hint),
tCE("wfe", 320f002, _wfe, 0, (), noargs, t_hint),
#define THUMB_VARIANT & arm_ext_v6t2
TUE("csdb", 320f014, f3af8014, 0, (), noargs, t_csdb),
+ TUF("ssbb", 57ff040, f3bf8f40, 0, (), noargs, t_csdb),
+ TUF("pssbb", 57ff044, f3bf8f44, 0, (), noargs, t_csdb),
#undef ARM_VARIANT
#define ARM_VARIANT & arm_ext_v6t2
#define THUMB_VARIANT & arm_ext_v8
tCE("sevl", 320f005, _sevl, 0, (), noargs, t_hint),
- TUE("hlt", 1000070, ba80, 1, (oIffffb), bkpt, t_hlt),
TCE("ldaexd", 1b00e9f, e8d000ff, 3, (RRnpc, oRRnpc, RRnpcb),
ldrexd, t_ldrexd),
TCE("stlexd", 1a00e90, e8c000f0, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb),
strexd, t_strexd),
- /* ARMv8 T32 only. */
+
+/* Defined in V8 but is in undefined encoding space for earlier
+ architectures. However earlier architectures are required to treat
+ this instuction as a semihosting trap as well. Hence while not explicitly
+ defined as such, it is in fact correct to define the instruction for all
+ architectures. */
+#undef THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v1
#undef ARM_VARIANT
-#define ARM_VARIANT NULL
+#define ARM_VARIANT & arm_ext_v1
+ TUE("hlt", 1000070, ba80, 1, (oIffffb), bkpt, t_hlt),
+
+ /* ARMv8 T32 only. */
+#undef ARM_VARIANT
+#define ARM_VARIANT NULL
TUF("dcps1", 0, f78f8001, 0, (), noargs, noargs),
TUF("dcps2", 0, f78f8002, 0, (), noargs, noargs),
TUF("dcps3", 0, f78f8003, 0, (), noargs, noargs),
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),
nCEF(vcvt, _vcvt, 3, (RNSDQ, RNSDQ, oI32z), neon_cvt),
nCEF(vcvtr, _vcvt, 2, (RNSDQ, RNSDQ), neon_cvtr),
NCE(vmov, 0, 1, (VMOV), neon_mov),
NCE(vmovq, 0, 1, (VMOV), neon_mov),
+#undef THUMB_VARIANT
+/* Could be either VLDR/VSTR or VLDR/VSTR (system register) which are guarded
+ by different feature bits. Since we are setting the Thumb guard, we can
+ require Thumb-1 which makes it a nop guard and set the right feature bit in
+ do_vldr_vstr (). */
+#define THUMB_VARIANT & arm_ext_v4t
+ NCE(vldr, d100b00, 2, (VLDR, ADDRGLDC), vldr_vstr),
+ NCE(vstr, d000b00, 2, (VLDR, ADDRGLDC), vldr_vstr),
+
#undef ARM_VARIANT
#define ARM_VARIANT & arm_ext_fp16
#undef THUMB_VARIANT
cCE("cfmadda32", e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
cCE("cfmsuba32", e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
+ /* ARMv8.5-A instructions. */
+#undef ARM_VARIANT
+#define ARM_VARIANT & arm_ext_sb
+#undef THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_sb
+ TUF("sb", 57ff070, f3bf8f70, 0, (), noargs, noargs),
+
+#undef ARM_VARIANT
+#define ARM_VARIANT & arm_ext_predres
+#undef THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_predres
+ CE("cfprctx", e070f93, 1, (RRnpc), rd),
+ CE("dvprctx", e070fb3, 1, (RRnpc), rd),
+ CE("cpprctx", e070ff3, 1, (RRnpc), rd),
+
/* ARMv8-M instructions. */
#undef ARM_VARIANT
#define ARM_VARIANT NULL
#undef THUMB_VARIANT
#define THUMB_VARIANT & arm_ext_v8m
- TUE("sg", 0, e97fe97f, 0, (), 0, noargs),
- TCE("blxns", 0, 4784, 1, (RRnpc), 0, t_blx),
- TCE("bxns", 0, 4704, 1, (RRnpc), 0, t_bx),
- TCE("tt", 0, e840f000, 2, (RRnpc, RRnpc), 0, tt),
- TCE("ttt", 0, e840f040, 2, (RRnpc, RRnpc), 0, tt),
- TCE("tta", 0, e840f080, 2, (RRnpc, RRnpc), 0, tt),
- TCE("ttat", 0, e840f0c0, 2, (RRnpc, RRnpc), 0, tt),
+ ToU("sg", e97fe97f, 0, (), noargs),
+ ToC("blxns", 4784, 1, (RRnpc), t_blx),
+ ToC("bxns", 4704, 1, (RRnpc), t_bx),
+ ToC("tt", e840f000, 2, (RRnpc, RRnpc), tt),
+ ToC("ttt", e840f040, 2, (RRnpc, RRnpc), tt),
+ ToC("tta", e840f080, 2, (RRnpc, RRnpc), tt),
+ ToC("ttat", e840f0c0, 2, (RRnpc, RRnpc), tt),
/* FP for ARMv8-M Mainline. Enabled for ARMv8-M Mainline because the
instructions behave as nop if no VFP is present. */
#undef THUMB_VARIANT
#define THUMB_VARIANT & arm_ext_v8m_main
- TCE("vlldm", 0, ec300a00, 1, (RRnpc), 0, rn),
- TCE("vlstm", 0, ec200a00, 1, (RRnpc), 0, rn),
+ ToC("vlldm", ec300a00, 1, (RRnpc), rn),
+ ToC("vlstm", ec200a00, 1, (RRnpc), rn),
+
+ /* Armv8.1-M Mainline instructions. */
+#undef THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8_1m_main
+ toC("bf", _bf, 2, (EXPs, EXPs), t_branch_future),
+ toU("bfcsel", _bfcsel, 4, (EXPs, EXPs, EXPs, COND), t_branch_future),
+ toC("bfx", _bfx, 2, (EXPs, RRnpcsp), t_branch_future),
+ toC("bfl", _bfl, 2, (EXPs, EXPs), t_branch_future),
+ toC("bflx", _bflx, 2, (EXPs, RRnpcsp), t_branch_future),
+
+ toU("dls", _dls, 2, (LR, RRnpcsp), t_loloop),
+ toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
+ toU("le", _le, 2, (oLR, EXP), t_loloop),
+
+ ToC("clrm", e89f0000, 1, (CLRMLST), t_clrm),
+ ToC("vscclrm", ec9f0a00, 1, (VRSDVLST), t_vscclrm)
};
#undef ARM_VARIANT
#undef THUMB_VARIANT
#undef cCE
#undef cCL
#undef C3E
+#undef C3
#undef CE
#undef CM
+#undef CL
#undef UE
#undef UF
#undef UT
#undef OPS5
#undef OPS6
#undef do_0
+#undef ToC
+#undef toC
+#undef ToU
+#undef toU
\f
/* MD interface: bits in the object file. */
md_section_align (segT segment ATTRIBUTE_UNUSED,
valueT size)
{
-#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
- if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
- {
- /* For a.out, force the section size to be aligned. If we don't do
- this, BFD will align it for us, but it will not write out the
- final bytes of the section. This may be a bug in BFD, but it is
- easier to fix it here since that is how the other a.out targets
- work. */
- int align;
-
- align = bfd_get_section_alignment (stdoutput, segment);
- size = ((size + (1 << align) - 1) & (-((valueT) 1 << align)));
- }
-#endif
-
return size;
}
return (base + 4) & ~3;
/* Thumb branches are simply offset by +4. */
+ case BFD_RELOC_THUMB_PCREL_BRANCH5:
case BFD_RELOC_THUMB_PCREL_BRANCH7:
case BFD_RELOC_THUMB_PCREL_BRANCH9:
case BFD_RELOC_THUMB_PCREL_BRANCH12:
case BFD_RELOC_THUMB_PCREL_BRANCH20:
case BFD_RELOC_THUMB_PCREL_BRANCH25:
+ case BFD_RELOC_THUMB_PCREL_BFCSEL:
+ case BFD_RELOC_ARM_THUMB_BF17:
+ case BFD_RELOC_ARM_THUMB_BF19:
+ case BFD_RELOC_ARM_THUMB_BF13:
+ case BFD_RELOC_ARM_THUMB_LOOP12:
return base + 4;
case BFD_RELOC_THUMB_PCREL_BRANCH23:
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)
+ if (hash_insert (already_warned, nbuf, NULL) == NULL)
as_warn (_("[-mwarn-syms]: Assignment makes a symbol match an ARM instruction: %s"), name);
}
else
/* MOV accepts both Thumb2 modified immediate (T2 encoding) and
UINT16 (T3 encoding), MOVW only accepts UINT16. When
disassembling, MOV is preferred when there is no encoding
- overlap.
- NOTE: MOV is using ORR opcode under Thumb 2 mode. */
+ overlap. */
if (((newval >> T2_DATA_OP_SHIFT) & 0xf) == T2_OPCODE_ORR
+ /* NOTE: MOV uses the ORR opcode in Thumb 2 mode
+ but with the Rn field [19:16] set to 1111. */
+ && (((newval >> 16) & 0xf) == 0xf)
&& ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2_v8m)
&& !((newval >> T2_SBIT_SHIFT) & 0x1)
- && value >= 0 && value <=0xffff)
+ && value >= 0 && value <= 0xffff)
{
/* Toggle bit[25] to change encoding from T2 to T3. */
newval ^= 1 << 25;
S_SET_THREAD_LOCAL (fixP->fx_addsy);
break;
+ /* Same handling as above, but with the arm_fdpic guard. */
+ case BFD_RELOC_ARM_TLS_GD32_FDPIC:
+ case BFD_RELOC_ARM_TLS_IE32_FDPIC:
+ case BFD_RELOC_ARM_TLS_LDM32_FDPIC:
+ if (arm_fdpic)
+ {
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ }
+ else
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Relocation supported only in FDPIC mode"));
+ }
+ break;
+
case BFD_RELOC_ARM_GOT32:
case BFD_RELOC_ARM_GOTOFF:
break;
if (fixP->fx_done || !seg->use_rela_p)
md_number_to_chars (buf, fixP->fx_offset, 4);
break;
+
+ /* Relocations for FDPIC. */
+ case BFD_RELOC_ARM_GOTFUNCDESC:
+ case BFD_RELOC_ARM_GOTOFFFUNCDESC:
+ case BFD_RELOC_ARM_FUNCDESC:
+ if (arm_fdpic)
+ {
+ if (fixP->fx_done || !seg->use_rela_p)
+ md_number_to_chars (buf, 0, 4);
+ }
+ else
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Relocation supported only in FDPIC mode"));
+ }
+ break;
#endif
case BFD_RELOC_RVA:
case BFD_RELOC_ARM_CP_OFF_IMM:
case BFD_RELOC_ARM_T32_CP_OFF_IMM:
+ case BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM:
if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM)
newval = md_chars_to_number (buf, INSN_SIZE);
else
as_bad_where (fixP->fx_file, fixP->fx_line,
_("co-processor offset out of range"));
}
+ else if ((newval & 0xfe001f80) == 0xec000f80)
+ {
+ if (value < -511 || value > 512 || (value & 3))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("co-processor offset out of range"));
+ }
else if (value < -1023 || value > 1023 || (value & 3))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("co-processor offset out of range"));
else
newval = get_thumb32_insn (buf);
if (value == 0)
- newval &= 0xffffff00;
+ {
+ if (fixP->fx_r_type == BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM)
+ newval &= 0xffffff80;
+ else
+ newval &= 0xffffff00;
+ }
else
{
- newval &= 0xff7fff00;
+ if (fixP->fx_r_type == BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM)
+ newval &= 0xff7fff80;
+ else
+ newval &= 0xff7fff00;
if ((newval & 0x0f200f00) == 0x0d000900)
{
/* This is a fp16 vstr/vldr.
{
bfd_vma insn;
bfd_vma encoded_addend;
- bfd_vma addend_abs = abs (value);
+ bfd_vma addend_abs = llabs (value);
/* Check that the absolute value of the addend can be
expressed as an 8-bit constant plus a rotation. */
if (!seg->use_rela_p)
{
bfd_vma insn;
- bfd_vma addend_abs = abs (value);
+ bfd_vma addend_abs = llabs (value);
/* Check that the absolute value of the addend can be
encoded in 12 bits. */
if (!seg->use_rela_p)
{
bfd_vma insn;
- bfd_vma addend_abs = abs (value);
+ bfd_vma addend_abs = llabs (value);
/* Check that the absolute value of the addend can be
encoded in 8 bits. */
if (!seg->use_rela_p)
{
bfd_vma insn;
- bfd_vma addend_abs = abs (value);
+ bfd_vma addend_abs = llabs (value);
/* Check that the absolute value of the addend is a multiple of
four and, when divided by four, fits in 8 bits. */
}
break;
+ case BFD_RELOC_THUMB_PCREL_BRANCH5:
+ if (fixP->fx_addsy
+ && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+ && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+ && ARM_IS_FUNC (fixP->fx_addsy)
+ && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+ {
+ /* Force a relocation for a branch 5 bits wide. */
+ fixP->fx_done = 0;
+ }
+ if (v8_1_branch_value_check (value, 5, FALSE) == FAIL)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ BAD_BRANCH_OFF);
+
+ if (fixP->fx_done || !seg->use_rela_p)
+ {
+ addressT boff = value >> 1;
+
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ newval |= (boff << 7);
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ }
+ break;
+
+ case BFD_RELOC_THUMB_PCREL_BFCSEL:
+ if (fixP->fx_addsy
+ && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+ && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+ && ARM_IS_FUNC (fixP->fx_addsy)
+ && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+ {
+ fixP->fx_done = 0;
+ }
+ if ((value & ~0x7f) && ((value & ~0x3f) != ~0x3f))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("branch out of range"));
+
+ if (fixP->fx_done || !seg->use_rela_p)
+ {
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+
+ addressT boff = ((newval & 0x0780) >> 7) << 1;
+ addressT diff = value - boff;
+
+ if (diff == 4)
+ {
+ newval |= 1 << 1; /* T bit. */
+ }
+ else if (diff != 2)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("out of range label-relative fixup value"));
+ }
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ }
+ break;
+
+ case BFD_RELOC_ARM_THUMB_BF17:
+ if (fixP->fx_addsy
+ && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+ && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+ && ARM_IS_FUNC (fixP->fx_addsy)
+ && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+ {
+ /* Force a relocation for a branch 17 bits wide. */
+ fixP->fx_done = 0;
+ }
+
+ if (v8_1_branch_value_check (value, 17, TRUE) == FAIL)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ BAD_BRANCH_OFF);
+
+ if (fixP->fx_done || !seg->use_rela_p)
+ {
+ offsetT newval2;
+ addressT immA, immB, immC;
+
+ immA = (value & 0x0001f000) >> 12;
+ immB = (value & 0x00000ffc) >> 2;
+ immC = (value & 0x00000002) >> 1;
+
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+ newval |= immA;
+ newval2 |= (immC << 11) | (immB << 1);
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+ }
+ break;
+
+ case BFD_RELOC_ARM_THUMB_BF19:
+ if (fixP->fx_addsy
+ && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+ && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+ && ARM_IS_FUNC (fixP->fx_addsy)
+ && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+ {
+ /* Force a relocation for a branch 19 bits wide. */
+ fixP->fx_done = 0;
+ }
+
+ if (v8_1_branch_value_check (value, 19, TRUE) == FAIL)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ BAD_BRANCH_OFF);
+
+ if (fixP->fx_done || !seg->use_rela_p)
+ {
+ offsetT newval2;
+ addressT immA, immB, immC;
+
+ immA = (value & 0x0007f000) >> 12;
+ immB = (value & 0x00000ffc) >> 2;
+ immC = (value & 0x00000002) >> 1;
+
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+ newval |= immA;
+ newval2 |= (immC << 11) | (immB << 1);
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+ }
+ break;
+
+ case BFD_RELOC_ARM_THUMB_BF13:
+ if (fixP->fx_addsy
+ && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+ && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+ && ARM_IS_FUNC (fixP->fx_addsy)
+ && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+ {
+ /* Force a relocation for a branch 13 bits wide. */
+ fixP->fx_done = 0;
+ }
+
+ if (v8_1_branch_value_check (value, 13, TRUE) == FAIL)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ BAD_BRANCH_OFF);
+
+ if (fixP->fx_done || !seg->use_rela_p)
+ {
+ offsetT newval2;
+ addressT immA, immB, immC;
+
+ immA = (value & 0x00001000) >> 12;
+ immB = (value & 0x00000ffc) >> 2;
+ immC = (value & 0x00000002) >> 1;
+
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+ newval |= immA;
+ newval2 |= (immC << 11) | (immB << 1);
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+ }
+ break;
+
+ case BFD_RELOC_ARM_THUMB_LOOP12:
+ if (fixP->fx_addsy
+ && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+ && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+ && ARM_IS_FUNC (fixP->fx_addsy)
+ && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+ {
+ /* Force a relocation for a branch 12 bits wide. */
+ fixP->fx_done = 0;
+ }
+
+ bfd_vma insn = get_thumb32_insn (buf);
+ /* le lr, <label> or le <label> */
+ if (((insn & 0xffffffff) == 0xf00fc001)
+ || ((insn & 0xffffffff) == 0xf02fc001))
+ value = -value;
+
+ if (v8_1_branch_value_check (value, 12, FALSE) == FAIL)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ BAD_BRANCH_OFF);
+ if (fixP->fx_done || !seg->use_rela_p)
+ {
+ addressT imml, immh;
+
+ immh = (value & 0x00000ffc) >> 2;
+ imml = (value & 0x00000002) >> 1;
+
+ newval = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+ newval |= (imml << 11) | (immh << 1);
+ md_number_to_chars (buf + THUMB_SIZE, newval, THUMB_SIZE);
+ }
+ break;
+
case BFD_RELOC_ARM_V4BX:
/* This will need to go in the object file. */
fixP->fx_done = 0;
case BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC:
case BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC:
case BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC:
+ case BFD_RELOC_ARM_GOTFUNCDESC:
+ case BFD_RELOC_ARM_GOTOFFFUNCDESC:
+ case BFD_RELOC_ARM_FUNCDESC:
+ case BFD_RELOC_ARM_THUMB_BF17:
+ case BFD_RELOC_ARM_THUMB_BF19:
+ case BFD_RELOC_ARM_THUMB_BF13:
code = fixp->fx_r_type;
break;
case BFD_RELOC_ARM_TLS_GOTDESC:
case BFD_RELOC_ARM_TLS_GD32:
+ case BFD_RELOC_ARM_TLS_GD32_FDPIC:
case BFD_RELOC_ARM_TLS_LE32:
case BFD_RELOC_ARM_TLS_IE32:
+ case BFD_RELOC_ARM_TLS_IE32_FDPIC:
case BFD_RELOC_ARM_TLS_LDM32:
+ case BFD_RELOC_ARM_TLS_LDM32_FDPIC:
/* BFD will include the symbol's address in the addend.
But we don't want that, so subtract it out again here. */
if (!S_IS_COMMON (fixp->fx_addsy))
_("ADRL used for a symbol not defined in the same file"));
return NULL;
+ case BFD_RELOC_THUMB_PCREL_BRANCH5:
+ case BFD_RELOC_THUMB_PCREL_BFCSEL:
+ case BFD_RELOC_ARM_THUMB_LOOP12:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("%s used for a symbol not defined in the same file"),
+ bfd_get_reloc_code_name (fixp->fx_r_type));
+ return NULL;
+
case BFD_RELOC_ARM_OFFSET_IMM:
if (section->use_rela_p)
{
|| fixP->fx_r_type == BFD_RELOC_ARM_GOT32
|| fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
|| fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
+ || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32_FDPIC
|| fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
|| fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
+ || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32_FDPIC
|| fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
+ || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32_FDPIC
|| fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
|| fixP->fx_r_type == BFD_RELOC_ARM_TLS_GOTDESC
|| fixP->fx_r_type == BFD_RELOC_ARM_TLS_CALL
? "elf32-bigarm-nacl"
: "elf32-littlearm-nacl");
#else
- if (target_big_endian)
- return "elf32-bigarm";
+ if (arm_fdpic)
+ {
+ if (target_big_endian)
+ return "elf32-bigarm-fdpic";
+ else
+ return "elf32-littlearm-fdpic";
+ }
else
- return "elf32-littlearm";
+ {
+ if (target_big_endian)
+ return "elf32-bigarm";
+ else
+ return "elf32-littlearm";
+ }
#endif
}
if (mcpu_cpu_opt || march_cpu_opt)
as_bad (_("use of old and new-style options to set CPU type"));
- mcpu_cpu_opt = legacy_cpu;
+ selected_arch = *legacy_cpu;
}
- else if (!mcpu_cpu_opt)
+ else if (mcpu_cpu_opt)
+ {
+ selected_arch = *mcpu_cpu_opt;
+ selected_ext = *mcpu_ext_opt;
+ }
+ else if (march_cpu_opt)
{
- mcpu_cpu_opt = march_cpu_opt;
- dyn_mcpu_ext_opt = dyn_march_ext_opt;
- /* Avoid double free in arm_md_end. */
- dyn_march_ext_opt = NULL;
+ selected_arch = *march_cpu_opt;
+ selected_ext = *march_ext_opt;
}
+ ARM_MERGE_FEATURE_SETS (selected_cpu, selected_arch, selected_ext);
if (legacy_fpu)
{
if (mfpu_opt)
as_bad (_("use of old and new-style options to set FPU type"));
- mfpu_opt = legacy_fpu;
+ selected_fpu = *legacy_fpu;
}
- else if (!mfpu_opt)
+ else if (mfpu_opt)
+ selected_fpu = *mfpu_opt;
+ else
{
#if !(defined (EABI_DEFAULT) || defined (TE_LINUX) \
|| defined (TE_NetBSD) || defined (TE_VXWORKS))
/* Some environments specify a default FPU. If they don't, infer it
from the processor. */
if (mcpu_fpu_opt)
- mfpu_opt = mcpu_fpu_opt;
- else
- mfpu_opt = march_fpu_opt;
+ selected_fpu = *mcpu_fpu_opt;
+ else if (march_fpu_opt)
+ selected_fpu = *march_fpu_opt;
#else
- mfpu_opt = &fpu_default;
+ selected_fpu = fpu_default;
#endif
}
- if (!mfpu_opt)
+ if (ARM_FEATURE_ZERO (selected_fpu))
{
- if (mcpu_cpu_opt != NULL)
- mfpu_opt = &fpu_default;
- else if (mcpu_fpu_opt != NULL && ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5))
- mfpu_opt = &fpu_arch_vfp_v2;
+ if (!no_cpu_selected ())
+ selected_fpu = fpu_default;
else
- mfpu_opt = &fpu_arch_fpa;
+ selected_fpu = fpu_arch_fpa;
}
#ifdef CPU_DEFAULT
- if (!mcpu_cpu_opt)
+ if (ARM_FEATURE_ZERO (selected_arch))
{
- mcpu_cpu_opt = &cpu_default;
- selected_cpu = cpu_default;
+ selected_arch = cpu_default;
+ selected_cpu = selected_arch;
}
- else if (dyn_mcpu_ext_opt)
- ARM_MERGE_FEATURE_SETS (selected_cpu, *mcpu_cpu_opt, *dyn_mcpu_ext_opt);
- else
- selected_cpu = *mcpu_cpu_opt;
+ ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
#else
- if (mcpu_cpu_opt && dyn_mcpu_ext_opt)
- ARM_MERGE_FEATURE_SETS (selected_cpu, *mcpu_cpu_opt, *dyn_mcpu_ext_opt);
- else if (mcpu_cpu_opt)
- selected_cpu = *mcpu_cpu_opt;
+ /* Autodection of feature mode: allow all features in cpu_variant but leave
+ selected_cpu unset. It will be set in aeabi_set_public_attributes ()
+ after all instruction have been processed and we can decide what CPU
+ should be selected. */
+ if (ARM_FEATURE_ZERO (selected_arch))
+ ARM_MERGE_FEATURE_SETS (cpu_variant, arm_arch_any, selected_fpu);
else
- mcpu_cpu_opt = &arm_arch_any;
+ ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
#endif
- ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
- if (dyn_mcpu_ext_opt)
- ARM_MERGE_FEATURE_SETS (cpu_variant, cpu_variant, *dyn_mcpu_ext_opt);
-
autoselect_thumb_from_cpu_variant ();
arm_arch_used = thumb_arch_used = arm_arch_none;
#endif
#endif
#define OPTION_FIX_V4BX (OPTION_MD_BASE + 2)
+#define OPTION_FDPIC (OPTION_MD_BASE + 3)
struct option md_longopts[] =
{
{"EL", no_argument, NULL, OPTION_EL},
#endif
{"fix-v4bx", no_argument, NULL, OPTION_FIX_V4BX},
+#ifdef OBJ_ELF
+ {"fdpic", no_argument, NULL, OPTION_FDPIC},
+#endif
{NULL, no_argument, NULL, 0}
};
ARM_CPU_OPT ("cortex-a75", "Cortex-A75", ARM_ARCH_V8_2A,
ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
+ ARM_CPU_OPT ("cortex-a76", "Cortex-A76", ARM_ARCH_V8_2A,
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+ FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
+ ARM_CPU_OPT ("ares", "Ares", ARM_ARCH_V8_2A,
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+ FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
ARM_CPU_OPT ("cortex-r4", "Cortex-R4", ARM_ARCH_V7R,
ARM_ARCH_NONE,
FPU_NONE),
ARM_CPU_OPT ("exynos-m1", "Samsung Exynos M1", ARM_ARCH_V8A,
ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
FPU_ARCH_CRYPTO_NEON_VFP_ARMV8),
-
+ ARM_CPU_OPT ("neoverse-n1", "Neoverse N1", ARM_ARCH_V8_2A,
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+ FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
/* ??? XSCALE is really an architecture. */
ARM_CPU_OPT ("xscale", NULL, ARM_ARCH_XSCALE,
ARM_ARCH_NONE,
};
#undef ARM_CPU_OPT
+struct arm_ext_table
+{
+ const char * name;
+ size_t name_len;
+ const arm_feature_set merge;
+ const arm_feature_set clear;
+};
+
struct arm_arch_option_table
{
- const char * name;
- size_t name_len;
- const arm_feature_set value;
- const arm_feature_set default_fpu;
+ const char * name;
+ size_t name_len;
+ const arm_feature_set value;
+ const arm_feature_set default_fpu;
+ const struct arm_ext_table * ext_table;
+};
+
+/* Used to add support for +E and +noE extension. */
+#define ARM_EXT(E, M, C) { E, sizeof (E) - 1, M, C }
+/* Used to add support for a +E extension. */
+#define ARM_ADD(E, M) { E, sizeof(E) - 1, M, ARM_ARCH_NONE }
+/* Used to add support for a +noE extension. */
+#define ARM_REMOVE(E, C) { E, sizeof(E) -1, ARM_ARCH_NONE, C }
+
+#define ALL_FP ARM_FEATURE (0, ARM_EXT2_FP16_INST | ARM_EXT2_FP16_FML, \
+ ~0 & ~FPU_ENDIAN_PURE)
+
+static const struct arm_ext_table armv5te_ext_table[] =
+{
+ ARM_EXT ("fp", FPU_ARCH_VFP_V2, ALL_FP),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7_ext_table[] =
+{
+ ARM_EXT ("fp", FPU_ARCH_VFP_V3D16, ALL_FP),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7ve_ext_table[] =
+{
+ ARM_EXT ("fp", FPU_ARCH_VFP_V4D16, ALL_FP),
+ ARM_ADD ("vfpv3-d16", FPU_ARCH_VFP_V3D16),
+ ARM_ADD ("vfpv3", FPU_ARCH_VFP_V3),
+ ARM_ADD ("vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16),
+ ARM_ADD ("vfpv3-fp16", FPU_ARCH_VFP_V3_FP16),
+ ARM_ADD ("vfpv4-d16", FPU_ARCH_VFP_V4D16), /* Alias for +fp. */
+ ARM_ADD ("vfpv4", FPU_ARCH_VFP_V4),
+
+ ARM_EXT ("simd", FPU_ARCH_NEON_VFP_V4,
+ ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_NEON_EXT_FMA)),
+
+ /* Aliases for +simd. */
+ ARM_ADD ("neon-vfpv4", FPU_ARCH_NEON_VFP_V4),
+
+ ARM_ADD ("neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1),
+ ARM_ADD ("neon-vfpv3", FPU_ARCH_VFP_V3_PLUS_NEON_V1),
+ ARM_ADD ("neon-fp16", FPU_ARCH_NEON_FP16),
+
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7a_ext_table[] =
+{
+ ARM_EXT ("fp", FPU_ARCH_VFP_V3D16, ALL_FP),
+ ARM_ADD ("vfpv3-d16", FPU_ARCH_VFP_V3D16), /* Alias for +fp. */
+ ARM_ADD ("vfpv3", FPU_ARCH_VFP_V3),
+ ARM_ADD ("vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16),
+ ARM_ADD ("vfpv3-fp16", FPU_ARCH_VFP_V3_FP16),
+ ARM_ADD ("vfpv4-d16", FPU_ARCH_VFP_V4D16),
+ ARM_ADD ("vfpv4", FPU_ARCH_VFP_V4),
+
+ ARM_EXT ("simd", FPU_ARCH_VFP_V3_PLUS_NEON_V1,
+ ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_NEON_EXT_FMA)),
+
+ /* Aliases for +simd. */
+ ARM_ADD ("neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1),
+ ARM_ADD ("neon-vfpv3", FPU_ARCH_VFP_V3_PLUS_NEON_V1),
+
+ ARM_ADD ("neon-fp16", FPU_ARCH_NEON_FP16),
+ ARM_ADD ("neon-vfpv4", FPU_ARCH_NEON_VFP_V4),
+
+ ARM_ADD ("mp", ARM_FEATURE_CORE_LOW (ARM_EXT_MP)),
+ ARM_ADD ("sec", ARM_FEATURE_CORE_LOW (ARM_EXT_SEC)),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7r_ext_table[] =
+{
+ ARM_ADD ("fp.sp", FPU_ARCH_VFP_V3xD),
+ ARM_ADD ("vfpv3xd", FPU_ARCH_VFP_V3xD), /* Alias for +fp.sp. */
+ ARM_EXT ("fp", FPU_ARCH_VFP_V3D16, ALL_FP),
+ ARM_ADD ("vfpv3-d16", FPU_ARCH_VFP_V3D16), /* Alias for +fp. */
+ ARM_ADD ("vfpv3xd-fp16", FPU_ARCH_VFP_V3xD_FP16),
+ ARM_ADD ("vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16),
+ ARM_EXT ("idiv", ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV)),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv7em_ext_table[] =
+{
+ ARM_EXT ("fp", FPU_ARCH_VFP_V4_SP_D16, ALL_FP),
+ /* Alias for +fp, used to be known as fpv4-sp-d16. */
+ ARM_ADD ("vfpv4-sp-d16", FPU_ARCH_VFP_V4_SP_D16),
+ ARM_ADD ("fpv5", FPU_ARCH_VFP_V5_SP_D16),
+ ARM_ADD ("fp.dp", FPU_ARCH_VFP_V5D16),
+ ARM_ADD ("fpv5-d16", FPU_ARCH_VFP_V5D16),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv8a_ext_table[] =
+{
+ ARM_ADD ("crc", ARCH_CRC_ARMV8),
+ ARM_ADD ("simd", FPU_ARCH_NEON_VFP_ARMV8),
+ ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+
+ /* Armv8-a does not allow an FP implementation without SIMD, so the user
+ should use the +simd option to turn on FP. */
+ ARM_REMOVE ("fp", ALL_FP),
+ ARM_ADD ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB)),
+ ARM_ADD ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES)),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+
+static const struct arm_ext_table armv81a_ext_table[] =
+{
+ ARM_ADD ("simd", FPU_ARCH_NEON_VFP_ARMV8_1),
+ ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_1,
+ ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+
+ /* Armv8-a does not allow an FP implementation without SIMD, so the user
+ should use the +simd option to turn on FP. */
+ ARM_REMOVE ("fp", ALL_FP),
+ ARM_ADD ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB)),
+ ARM_ADD ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES)),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv82a_ext_table[] =
+{
+ ARM_ADD ("simd", FPU_ARCH_NEON_VFP_ARMV8_1),
+ ARM_ADD ("fp16", FPU_ARCH_NEON_VFP_ARMV8_2_FP16),
+ ARM_ADD ("fp16fml", FPU_ARCH_NEON_VFP_ARMV8_2_FP16FML),
+ ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_1,
+ ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+ ARM_ADD ("dotprod", FPU_ARCH_DOTPROD_NEON_VFP_ARMV8),
+
+ /* Armv8-a does not allow an FP implementation without SIMD, so the user
+ should use the +simd option to turn on FP. */
+ ARM_REMOVE ("fp", ALL_FP),
+ ARM_ADD ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB)),
+ ARM_ADD ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES)),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv84a_ext_table[] =
+{
+ ARM_ADD ("simd", FPU_ARCH_DOTPROD_NEON_VFP_ARMV8),
+ ARM_ADD ("fp16", FPU_ARCH_NEON_VFP_ARMV8_4_FP16FML),
+ ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_4,
+ ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+
+ /* Armv8-a does not allow an FP implementation without SIMD, so the user
+ should use the +simd option to turn on FP. */
+ ARM_REMOVE ("fp", ALL_FP),
+ ARM_ADD ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB)),
+ ARM_ADD ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES)),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv85a_ext_table[] =
+{
+ ARM_ADD ("simd", FPU_ARCH_DOTPROD_NEON_VFP_ARMV8),
+ ARM_ADD ("fp16", FPU_ARCH_NEON_VFP_ARMV8_4_FP16FML),
+ ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_4,
+ ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+
+ /* Armv8-a does not allow an FP implementation without SIMD, so the user
+ should use the +simd option to turn on FP. */
+ ARM_REMOVE ("fp", ALL_FP),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv8m_main_ext_table[] =
+{
+ ARM_EXT ("dsp", ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP)),
+ ARM_EXT ("fp", FPU_ARCH_VFP_V5_SP_D16, ALL_FP),
+ ARM_ADD ("fp.dp", FPU_ARCH_VFP_V5D16),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv8_1m_main_ext_table[] =
+{
+ ARM_EXT ("dsp", ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP)),
+ ARM_EXT ("fp",
+ ARM_FEATURE (0, ARM_EXT2_FP16_INST,
+ FPU_VFP_V5_SP_D16 | FPU_VFP_EXT_FP16 | FPU_VFP_EXT_FMA),
+ ALL_FP),
+ ARM_ADD ("fp.dp",
+ ARM_FEATURE (0, ARM_EXT2_FP16_INST,
+ FPU_VFP_V5D16 | FPU_VFP_EXT_FP16 | FPU_VFP_EXT_FMA)),
+ ARM_EXT ("mve", ARM_FEATURE_COPROC (FPU_MVE),
+ ARM_FEATURE_COPROC (FPU_MVE | FPU_MVE_FP)),
+ ARM_ADD ("mve.fp",
+ ARM_FEATURE (0, ARM_EXT2_FP16_INST,
+ FPU_MVE | FPU_MVE_FP | FPU_VFP_V5_SP_D16 |
+ FPU_VFP_EXT_FP16 | FPU_VFP_EXT_FMA)),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+};
+
+static const struct arm_ext_table armv8r_ext_table[] =
+{
+ ARM_ADD ("crc", ARCH_CRC_ARMV8),
+ ARM_ADD ("simd", FPU_ARCH_NEON_VFP_ARMV8),
+ ARM_EXT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+ ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8)),
+ ARM_REMOVE ("fp", ALL_FP),
+ ARM_ADD ("fp.sp", FPU_ARCH_VFP_V5_SP_D16),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
};
/* This list should, at a minimum, contain all the architecture names
recognized by GCC. */
-#define ARM_ARCH_OPT(N, V, DF) { N, sizeof (N) - 1, V, DF }
+#define ARM_ARCH_OPT(N, V, DF) { N, sizeof (N) - 1, V, DF, NULL }
+#define ARM_ARCH_OPT2(N, V, DF, ext) \
+ { N, sizeof (N) - 1, V, DF, ext##_ext_table }
static const struct arm_arch_option_table arm_archs[] =
{
- ARM_ARCH_OPT ("all", ARM_ANY, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv1", ARM_ARCH_V1, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv2", ARM_ARCH_V2, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv3", ARM_ARCH_V3, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv4", ARM_ARCH_V4, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA),
- ARM_ARCH_OPT ("armv5", ARM_ARCH_V5, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv6", ARM_ARCH_V6, FPU_ARCH_VFP),
- 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 ("all", ARM_ANY, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv1", ARM_ARCH_V1, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv2", ARM_ARCH_V2, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv3", ARM_ARCH_V3, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv4", ARM_ARCH_V4, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA),
+ ARM_ARCH_OPT ("armv5", ARM_ARCH_V5, FPU_ARCH_VFP),
+ ARM_ARCH_OPT ("armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP),
+ ARM_ARCH_OPT ("armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP),
+ ARM_ARCH_OPT2 ("armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6", ARM_ARCH_V6, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6j", ARM_ARCH_V6, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6k", ARM_ARCH_V6K, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6z", ARM_ARCH_V6Z, FPU_ARCH_VFP, armv5te),
/* 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_OPT2 ("armv6kz", ARM_ARCH_V6KZ, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6zk", ARM_ARCH_V6KZ, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6t2", ARM_ARCH_V6T2, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP, armv5te),
/* 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_OPT2 ("armv6kzt2", ARM_ARCH_V6KZT2, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT2 ("armv6zkt2", ARM_ARCH_V6KZT2, FPU_ARCH_VFP, armv5te),
+ ARM_ARCH_OPT ("armv6-m", ARM_ARCH_V6M, FPU_ARCH_VFP),
+ ARM_ARCH_OPT ("armv6s-m", ARM_ARCH_V6SM, FPU_ARCH_VFP),
+ ARM_ARCH_OPT2 ("armv7", ARM_ARCH_V7, FPU_ARCH_VFP, armv7),
/* The official spelling of the ARMv7 profile variants is the dashed form.
Accept the non-dashed form for compatibility with old toolchains. */
- ARM_ARCH_OPT ("armv7a", ARM_ARCH_V7A, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv7ve", ARM_ARCH_V7VE, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv7r", ARM_ARCH_V7R, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv7m", ARM_ARCH_V7M, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv7-a", ARM_ARCH_V7A, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv7-r", ARM_ARCH_V7R, 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-m.base", ARM_ARCH_V8M_BASE, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv8-m.main", ARM_ARCH_V8M_MAIN, 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 ("armv8.3-a", ARM_ARCH_V8_3A, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv8-r", ARM_ARCH_V8R, FPU_ARCH_VFP),
- ARM_ARCH_OPT ("armv8.4-a", ARM_ARCH_V8_4A, 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),
- { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
+ ARM_ARCH_OPT2 ("armv7a", ARM_ARCH_V7A, FPU_ARCH_VFP, armv7a),
+ ARM_ARCH_OPT2 ("armv7ve", ARM_ARCH_V7VE, FPU_ARCH_VFP, armv7ve),
+ ARM_ARCH_OPT2 ("armv7r", ARM_ARCH_V7R, FPU_ARCH_VFP, armv7r),
+ ARM_ARCH_OPT ("armv7m", ARM_ARCH_V7M, FPU_ARCH_VFP),
+ ARM_ARCH_OPT2 ("armv7-a", ARM_ARCH_V7A, FPU_ARCH_VFP, armv7a),
+ ARM_ARCH_OPT2 ("armv7-r", ARM_ARCH_V7R, FPU_ARCH_VFP, armv7r),
+ ARM_ARCH_OPT ("armv7-m", ARM_ARCH_V7M, FPU_ARCH_VFP),
+ ARM_ARCH_OPT2 ("armv7e-m", ARM_ARCH_V7EM, FPU_ARCH_VFP, armv7em),
+ ARM_ARCH_OPT ("armv8-m.base", ARM_ARCH_V8M_BASE, FPU_ARCH_VFP),
+ ARM_ARCH_OPT2 ("armv8-m.main", ARM_ARCH_V8M_MAIN, FPU_ARCH_VFP,
+ armv8m_main),
+ ARM_ARCH_OPT2 ("armv8.1-m.main", ARM_ARCH_V8_1M_MAIN, FPU_ARCH_VFP,
+ armv8_1m_main),
+ ARM_ARCH_OPT2 ("armv8-a", ARM_ARCH_V8A, FPU_ARCH_VFP, armv8a),
+ ARM_ARCH_OPT2 ("armv8.1-a", ARM_ARCH_V8_1A, FPU_ARCH_VFP, armv81a),
+ ARM_ARCH_OPT2 ("armv8.2-a", ARM_ARCH_V8_2A, FPU_ARCH_VFP, armv82a),
+ ARM_ARCH_OPT2 ("armv8.3-a", ARM_ARCH_V8_3A, FPU_ARCH_VFP, armv82a),
+ ARM_ARCH_OPT2 ("armv8-r", ARM_ARCH_V8R, FPU_ARCH_VFP, armv8r),
+ ARM_ARCH_OPT2 ("armv8.4-a", ARM_ARCH_V8_4A, FPU_ARCH_VFP, armv84a),
+ ARM_ARCH_OPT2 ("armv8.5-a", ARM_ARCH_V8_5A, FPU_ARCH_VFP, armv85a),
+ 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),
+ { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
};
#undef ARM_ARCH_OPT
#define ARM_EXT_OPT(N, M, C, AA) { N, sizeof (N) - 1, M, C, { AA, ARM_ANY } }
#define ARM_EXT_OPT2(N, M, C, AA1, AA2) { N, sizeof (N) - 1, M, C, {AA1, AA2} }
+/* DEPRECATED: Refrain from using this table to add any new extensions, instead
+ use the context sensitive approach using arm_ext_table's. */
static const struct arm_option_extension_value_table arm_extensions[] =
{
ARM_EXT_OPT ("crc", ARCH_CRC_ARMV8, ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
ARM_EXT_OPT ("pan", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN),
ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_PAN, 0),
ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8A)),
+ ARM_EXT_OPT ("predres", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES),
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES),
+ ARM_ARCH_V8A),
ARM_EXT_OPT ("ras", ARM_FEATURE_CORE_HIGH (ARM_EXT2_RAS),
ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_RAS, 0),
ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8A)),
ARM_EXT_OPT ("rdma", FPU_ARCH_NEON_VFP_ARMV8_1,
ARM_FEATURE_COPROC (FPU_NEON_ARMV8 | FPU_NEON_EXT_RDMA),
ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8A)),
+ ARM_EXT_OPT ("sb", ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB),
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB),
+ ARM_ARCH_V8A),
ARM_EXT_OPT2 ("sec", ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
ARM_FEATURE_CORE_LOW (ARM_EXT_V6K),
static bfd_boolean
arm_parse_extension (const char *str, const arm_feature_set *opt_set,
- arm_feature_set **ext_set_p)
+ arm_feature_set *ext_set,
+ const struct arm_ext_table *ext_table)
{
/* We insist on extensions being specified in alphabetical order, and with
extensions being added before being removed. We achieve this by having
const arm_feature_set arm_any = ARM_ANY;
int adding_value = -1;
- if (!*ext_set_p)
- {
- *ext_set_p = XNEW (arm_feature_set);
- **ext_set_p = arm_arch_none;
- }
-
while (str != NULL && *str != 0)
{
const char *ext;
gas_assert (adding_value != -1);
gas_assert (opt != NULL);
+ if (ext_table != NULL)
+ {
+ const struct arm_ext_table * ext_opt = ext_table;
+ bfd_boolean found = FALSE;
+ for (; ext_opt->name != NULL; ext_opt++)
+ if (ext_opt->name_len == len
+ && strncmp (ext_opt->name, str, len) == 0)
+ {
+ if (adding_value)
+ {
+ if (ARM_FEATURE_ZERO (ext_opt->merge))
+ /* TODO: Option not supported. When we remove the
+ legacy table this case should error out. */
+ continue;
+
+ ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, ext_opt->merge);
+ }
+ else
+ {
+ if (ARM_FEATURE_ZERO (ext_opt->clear))
+ /* TODO: Option not supported. When we remove the
+ legacy table this case should error out. */
+ continue;
+ ARM_CLEAR_FEATURE (*ext_set, *ext_set, ext_opt->clear);
+ }
+ found = TRUE;
+ break;
+ }
+ if (found)
+ {
+ str = ext;
+ continue;
+ }
+ }
+
/* Scan over the options table trying to find an exact match. */
for (; opt->name != NULL; opt++)
if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
/* Add or remove the extension. */
if (adding_value)
- ARM_MERGE_FEATURE_SETS (**ext_set_p, **ext_set_p,
- opt->merge_value);
+ ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->merge_value);
else
- ARM_CLEAR_FEATURE (**ext_set_p, **ext_set_p, opt->clear_value);
+ ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->clear_value);
/* Allowing Thumb division instructions for ARMv7 in autodetection
rely on this break so that duplicate extensions (extensions
if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
{
mcpu_cpu_opt = &opt->value;
- if (!dyn_mcpu_ext_opt)
- dyn_mcpu_ext_opt = XNEW (arm_feature_set);
- *dyn_mcpu_ext_opt = opt->ext;
+ if (mcpu_ext_opt == NULL)
+ mcpu_ext_opt = XNEW (arm_feature_set);
+ *mcpu_ext_opt = opt->ext;
mcpu_fpu_opt = &opt->default_fpu;
if (opt->canonical_name)
{
}
if (ext != NULL)
- return arm_parse_extension (ext, mcpu_cpu_opt, &dyn_mcpu_ext_opt);
+ return arm_parse_extension (ext, mcpu_cpu_opt, mcpu_ext_opt, NULL);
return TRUE;
}
if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
{
march_cpu_opt = &opt->value;
+ if (march_ext_opt == NULL)
+ march_ext_opt = XNEW (arm_feature_set);
+ *march_ext_opt = arm_arch_none;
march_fpu_opt = &opt->default_fpu;
strcpy (selected_cpu_name, opt->name);
if (ext != NULL)
- return arm_parse_extension (ext, march_cpu_opt, &dyn_march_ext_opt);
+ return arm_parse_extension (ext, march_cpu_opt, march_ext_opt,
+ opt->ext_table);
return TRUE;
}
fix_v4bx = TRUE;
break;
+#ifdef OBJ_ELF
+ case OPTION_FDPIC:
+ arm_fdpic = TRUE;
+ break;
+#endif /* OBJ_ELF */
+
case 'a':
/* Listing option. Just ignore these, we don't support additional
ones. */
fprintf (fp, _("\
--fix-v4bx Allow BX in ARMv4 code\n"));
+
+#ifdef OBJ_ELF
+ fprintf (fp, _("\
+ --fdpic generate an FDPIC object file\n"));
+#endif /* OBJ_ELF */
}
#ifdef OBJ_ELF
stable when new architectures are added. */
static const cpu_arch_ver_table cpu_arch_ver[] =
{
- {0, ARM_ARCH_V1},
- {0, ARM_ARCH_V2},
- {0, ARM_ARCH_V2S},
- {0, ARM_ARCH_V3},
- {0, ARM_ARCH_V3M},
- {1, ARM_ARCH_V4xM},
- {1, ARM_ARCH_V4},
- {2, ARM_ARCH_V4TxM},
- {2, ARM_ARCH_V4T},
- {3, ARM_ARCH_V5xM},
- {3, ARM_ARCH_V5},
- {3, ARM_ARCH_V5TxM},
- {3, ARM_ARCH_V5T},
- {4, ARM_ARCH_V5TExP},
- {4, ARM_ARCH_V5TE},
- {5, ARM_ARCH_V5TEJ},
- {6, ARM_ARCH_V6},
- {7, ARM_ARCH_V6Z},
- {7, ARM_ARCH_V6KZ},
- {9, ARM_ARCH_V6K},
- {8, ARM_ARCH_V6T2},
- {8, ARM_ARCH_V6KT2},
- {8, ARM_ARCH_V6ZT2},
- {8, ARM_ARCH_V6KZT2},
+ {TAG_CPU_ARCH_PRE_V4, ARM_ARCH_V1},
+ {TAG_CPU_ARCH_PRE_V4, ARM_ARCH_V2},
+ {TAG_CPU_ARCH_PRE_V4, ARM_ARCH_V2S},
+ {TAG_CPU_ARCH_PRE_V4, ARM_ARCH_V3},
+ {TAG_CPU_ARCH_PRE_V4, ARM_ARCH_V3M},
+ {TAG_CPU_ARCH_V4, ARM_ARCH_V4xM},
+ {TAG_CPU_ARCH_V4, ARM_ARCH_V4},
+ {TAG_CPU_ARCH_V4T, ARM_ARCH_V4TxM},
+ {TAG_CPU_ARCH_V4T, ARM_ARCH_V4T},
+ {TAG_CPU_ARCH_V5T, ARM_ARCH_V5xM},
+ {TAG_CPU_ARCH_V5T, ARM_ARCH_V5},
+ {TAG_CPU_ARCH_V5T, ARM_ARCH_V5TxM},
+ {TAG_CPU_ARCH_V5T, ARM_ARCH_V5T},
+ {TAG_CPU_ARCH_V5TE, ARM_ARCH_V5TExP},
+ {TAG_CPU_ARCH_V5TE, ARM_ARCH_V5TE},
+ {TAG_CPU_ARCH_V5TEJ, ARM_ARCH_V5TEJ},
+ {TAG_CPU_ARCH_V6, ARM_ARCH_V6},
+ {TAG_CPU_ARCH_V6KZ, ARM_ARCH_V6Z},
+ {TAG_CPU_ARCH_V6KZ, ARM_ARCH_V6KZ},
+ {TAG_CPU_ARCH_V6K, ARM_ARCH_V6K},
+ {TAG_CPU_ARCH_V6T2, ARM_ARCH_V6T2},
+ {TAG_CPU_ARCH_V6T2, ARM_ARCH_V6KT2},
+ {TAG_CPU_ARCH_V6T2, ARM_ARCH_V6ZT2},
+ {TAG_CPU_ARCH_V6T2, ARM_ARCH_V6KZT2},
/* When assembling a file with only ARMv6-M or ARMv6S-M instruction, GNU as
always selected build attributes to match those of ARMv6-M
would be selected when fully respecting chronology of architectures.
It is thus necessary to make a special case of ARMv6-M and ARMv6S-M and
move them before ARMv7 architectures. */
- {11, ARM_ARCH_V6M},
- {12, ARM_ARCH_V6SM},
-
- {10, ARM_ARCH_V7},
- {10, ARM_ARCH_V7A},
- {10, ARM_ARCH_V7R},
- {10, ARM_ARCH_V7M},
- {10, ARM_ARCH_V7VE},
- {13, ARM_ARCH_V7EM},
- {14, ARM_ARCH_V8A},
- {14, ARM_ARCH_V8_1A},
- {14, ARM_ARCH_V8_2A},
- {14, ARM_ARCH_V8_3A},
- {16, ARM_ARCH_V8M_BASE},
- {17, ARM_ARCH_V8M_MAIN},
- {15, ARM_ARCH_V8R},
- {16, ARM_ARCH_V8_4A},
- {-1, ARM_ARCH_NONE}
+ {TAG_CPU_ARCH_V6_M, ARM_ARCH_V6M},
+ {TAG_CPU_ARCH_V6S_M, ARM_ARCH_V6SM},
+
+ {TAG_CPU_ARCH_V7, ARM_ARCH_V7},
+ {TAG_CPU_ARCH_V7, ARM_ARCH_V7A},
+ {TAG_CPU_ARCH_V7, ARM_ARCH_V7R},
+ {TAG_CPU_ARCH_V7, ARM_ARCH_V7M},
+ {TAG_CPU_ARCH_V7, ARM_ARCH_V7VE},
+ {TAG_CPU_ARCH_V7E_M, ARM_ARCH_V7EM},
+ {TAG_CPU_ARCH_V8, ARM_ARCH_V8A},
+ {TAG_CPU_ARCH_V8, ARM_ARCH_V8_1A},
+ {TAG_CPU_ARCH_V8, ARM_ARCH_V8_2A},
+ {TAG_CPU_ARCH_V8, ARM_ARCH_V8_3A},
+ {TAG_CPU_ARCH_V8M_BASE, ARM_ARCH_V8M_BASE},
+ {TAG_CPU_ARCH_V8M_MAIN, ARM_ARCH_V8M_MAIN},
+ {TAG_CPU_ARCH_V8R, ARM_ARCH_V8R},
+ {TAG_CPU_ARCH_V8, ARM_ARCH_V8_4A},
+ {TAG_CPU_ARCH_V8, ARM_ARCH_V8_5A},
+ {TAG_CPU_ARCH_V8_1M_MAIN, ARM_ARCH_V8_1M_MAIN},
+ {-1, ARM_ARCH_NONE}
};
/* Set an attribute if it has not already been set by the user. */
if (ARM_FEATURE_EQUAL (*arch_ext_fset, arm_arch_any))
{
/* Force revisiting of decision for each new architecture. */
- gas_assert (MAX_TAG_CPU_ARCH <= TAG_CPU_ARCH_V8M_MAIN);
+ gas_assert (MAX_TAG_CPU_ARCH <= TAG_CPU_ARCH_V8_1M_MAIN);
*profile = 'A';
return TAG_CPU_ARCH_V8;
}
ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v4t);
/* Code run during relaxation relies on selected_cpu being set. */
+ ARM_CLEAR_FEATURE (flags_arch, flags, fpu_any);
+ flags_ext = arm_arch_none;
+ ARM_CLEAR_FEATURE (selected_arch, flags_arch, flags_ext);
+ selected_ext = flags_ext;
selected_cpu = flags;
}
/* Otherwise, choose the architecture based on the capabilities of the
requested cpu. */
else
- flags = selected_cpu;
- ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt);
+ {
+ ARM_MERGE_FEATURE_SETS (flags_arch, selected_arch, selected_ext);
+ ARM_CLEAR_FEATURE (flags_arch, flags_arch, fpu_any);
+ flags_ext = selected_ext;
+ flags = selected_cpu;
+ }
+ ARM_MERGE_FEATURE_SETS (flags, flags, selected_fpu);
/* Allow the user to override the reported architecture. */
- if (object_arch)
+ if (!ARM_FEATURE_ZERO (selected_object_arch))
{
- ARM_CLEAR_FEATURE (flags_arch, *object_arch, fpu_any);
+ ARM_CLEAR_FEATURE (flags_arch, selected_object_arch, fpu_any);
flags_ext = arm_arch_none;
}
else
- {
- ARM_CLEAR_FEATURE (flags_arch, flags, fpu_any);
- flags_ext = dyn_mcpu_ext_opt ? *dyn_mcpu_ext_opt : arm_arch_none;
- skip_exact_match = ARM_FEATURE_EQUAL (selected_cpu, arm_arch_any);
- }
+ skip_exact_match = ARM_FEATURE_EQUAL (selected_cpu, arm_arch_any);
/* When this function is run again after relaxation has happened there is no
way to determine whether an architecture or CPU was specified by the user:
aeabi_set_attribute_int (Tag_CPU_arch_profile, profile);
/* Tag_DSP_extension. */
- if (dyn_mcpu_ext_opt && ARM_CPU_HAS_FEATURE (*dyn_mcpu_ext_opt, arm_ext_dsp))
+ if (ARM_CPU_HAS_FEATURE (selected_ext, arm_ext_dsp))
aeabi_set_attribute_int (Tag_DSP_extension, 1);
ARM_CLEAR_FEATURE (flags_arch, flags, fpu_any);
}
}
+ if (ARM_CPU_HAS_FEATURE (flags, mve_fp_ext))
+ aeabi_set_attribute_int (Tag_MVE_arch, 2);
+ else if (ARM_CPU_HAS_FEATURE (flags, mve_ext))
+ aeabi_set_attribute_int (Tag_MVE_arch, 1);
+
/* Tag_VFP_HP_extension (formerly Tag_NEON_FP16_arch). */
if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16) && fp16_optional)
aeabi_set_attribute_int (Tag_VFP_HP_extension, 1);
by the base architecture.
For new architectures we will have to check these tests. */
- gas_assert (arch <= TAG_CPU_ARCH_V8M_MAIN);
+ gas_assert (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
|| ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m))
aeabi_set_attribute_int (Tag_DIV_use, 0);
arm_md_post_relax (void)
{
aeabi_set_public_attributes ();
- XDELETE (dyn_mcpu_ext_opt);
- dyn_mcpu_ext_opt = NULL;
- XDELETE (dyn_march_ext_opt);
- dyn_march_ext_opt = NULL;
+ XDELETE (mcpu_ext_opt);
+ mcpu_ext_opt = NULL;
+ XDELETE (march_ext_opt);
+ march_ext_opt = NULL;
}
/* Add the default contents for the .ARM.attributes section. */
for (opt = arm_cpus + 1; opt->name != NULL; opt++)
if (streq (opt->name, name))
{
- mcpu_cpu_opt = &opt->value;
- if (!dyn_mcpu_ext_opt)
- dyn_mcpu_ext_opt = XNEW (arm_feature_set);
- *dyn_mcpu_ext_opt = opt->ext;
- ARM_MERGE_FEATURE_SETS (selected_cpu, *mcpu_cpu_opt, *dyn_mcpu_ext_opt);
+ selected_arch = opt->value;
+ selected_ext = opt->ext;
+ ARM_MERGE_FEATURE_SETS (selected_cpu, selected_arch, selected_ext);
if (opt->canonical_name)
strcpy (selected_cpu_name, opt->canonical_name);
else
selected_cpu_name[i] = 0;
}
- ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
- if (dyn_mcpu_ext_opt)
- ARM_MERGE_FEATURE_SETS (cpu_variant, cpu_variant, *dyn_mcpu_ext_opt);
+ ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
+
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
return;
for (opt = arm_archs + 1; opt->name != NULL; opt++)
if (streq (opt->name, name))
{
- mcpu_cpu_opt = &opt->value;
- XDELETE (dyn_mcpu_ext_opt);
- dyn_mcpu_ext_opt = NULL;
- selected_cpu = *mcpu_cpu_opt;
+ selected_arch = opt->value;
+ selected_ext = arm_arch_none;
+ selected_cpu = selected_arch;
strcpy (selected_cpu_name, opt->name);
- ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, *mfpu_opt);
+ ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
return;
for (opt = arm_archs + 1; opt->name != NULL; opt++)
if (streq (opt->name, name))
{
- object_arch = &opt->value;
+ selected_object_arch = opt->value;
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
return;
s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
{
const struct arm_option_extension_value_table *opt;
- const arm_feature_set arm_any = ARM_ANY;
char saved_char;
char *name;
int adding_value = 1;
for (i = 0; i < nb_allowed_archs; i++)
{
/* Empty entry. */
- if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_any))
+ if (ARM_CPU_IS_ANY (opt->allowed_archs[i]))
continue;
- if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *mcpu_cpu_opt))
+ if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], selected_arch))
break;
}
break;
}
- if (!dyn_mcpu_ext_opt)
- {
- dyn_mcpu_ext_opt = XNEW (arm_feature_set);
- *dyn_mcpu_ext_opt = arm_arch_none;
- }
if (adding_value)
- ARM_MERGE_FEATURE_SETS (*dyn_mcpu_ext_opt, *dyn_mcpu_ext_opt,
+ ARM_MERGE_FEATURE_SETS (selected_ext, selected_ext,
opt->merge_value);
else
- ARM_CLEAR_FEATURE (*dyn_mcpu_ext_opt, *dyn_mcpu_ext_opt,
- opt->clear_value);
+ ARM_CLEAR_FEATURE (selected_ext, selected_ext, opt->clear_value);
- ARM_MERGE_FEATURE_SETS (selected_cpu, *mcpu_cpu_opt, *dyn_mcpu_ext_opt);
- ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, *mfpu_opt);
+ ARM_MERGE_FEATURE_SETS (selected_cpu, selected_arch, selected_ext);
+ ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
/* Allowing Thumb division instructions for ARMv7 in autodetection rely
for (opt = arm_fpus; opt->name != NULL; opt++)
if (streq (opt->name, name))
{
- mfpu_opt = &opt->value;
- ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
- if (dyn_mcpu_ext_opt)
- ARM_MERGE_FEATURE_SETS (cpu_variant, cpu_variant, *dyn_mcpu_ext_opt);
+ selected_fpu = opt->value;
+#ifndef CPU_DEFAULT
+ if (no_cpu_selected ())
+ ARM_MERGE_FEATURE_SETS (cpu_variant, arm_arch_any, selected_fpu);
+ else
+#endif
+ ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, selected_fpu);
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
return;
T (Tag_T2EE_use),
T (Tag_Virtualization_use),
T (Tag_DSP_extension),
+ T (Tag_MVE_arch),
/* We deliberately do not include Tag_MPextension_use_legacy. */
#undef T
};