/* tc-aarch64.c -- Assemble for the AArch64 ISA
- Copyright (C) 2009-2017 Free Software Foundation, Inc.
+ Copyright (C) 2009-2018 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of GAS.
| REG_TYPE(Z_32) | REG_TYPE(Z_64) | REG_TYPE(VN) \
| REG_TYPE(FP_B) | REG_TYPE(FP_H) \
| REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q)) \
- /* Typecheck: as above, but also Zn and Pn. This should only be \
- used for SVE instructions, since Zn and Pn are valid symbols \
+ /* Typecheck: as above, but also Zn, Pn, and {W}SP. This should only \
+ be used for SVE instructions, since Zn and Pn are valid symbols \
in other contexts. */ \
- MULTI_REG_TYPE(R_Z_BHSDQ_VZP, REG_TYPE(R_32) | REG_TYPE(R_64) \
+ MULTI_REG_TYPE(R_Z_SP_BHSDQ_VZP, REG_TYPE(R_32) | REG_TYPE(R_64) \
+ | REG_TYPE(SP_32) | REG_TYPE(SP_64) \
| REG_TYPE(Z_32) | REG_TYPE(Z_64) | REG_TYPE(VN) \
| REG_TYPE(FP_B) | REG_TYPE(FP_H) \
| REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q) \
"register expected");
break;
case REG_TYPE_R_Z_BHSDQ_V:
- case REG_TYPE_R_Z_BHSDQ_VZP:
+ case REG_TYPE_R_Z_SP_BHSDQ_VZP:
msg = N_("register expected");
break;
case REG_TYPE_BHSDQ: /* any [BHSDQ]P FP */
char *str = *ccp;
char *fpnum;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
- int found_fpchar = 0;
int64_t val = 0;
unsigned fpword = 0;
bfd_boolean hex_p = FALSE;
hex_p = TRUE;
}
- else
- {
- if (reg_name_p (str, reg_type))
- {
- set_recoverable_error (_("immediate operand required"));
- return FALSE;
- }
-
- /* We must not accidentally parse an integer as a floating-point number.
- Make sure that the value we parse is not an integer by checking for
- special characters '.' or 'e'. */
- for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
- if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
- {
- found_fpchar = 1;
- break;
- }
-
- if (!found_fpchar)
- return FALSE;
+ else if (reg_name_p (str, reg_type))
+ {
+ set_recoverable_error (_("immediate operand required"));
+ return FALSE;
}
if (! hex_p)
0,
0},
+ /* Most significant bits 0-15 of signed/unsigned address/value: MOVZ */
+ {"prel_g0", 1,
+ 0, /* adr_type */
+ 0,
+ BFD_RELOC_AARCH64_MOVW_PREL_G0,
+ 0,
+ 0,
+ 0},
+
+ /* Most significant bits 0-15 of signed/unsigned address/value: MOVK */
+ {"prel_g0_nc", 1,
+ 0, /* adr_type */
+ 0,
+ BFD_RELOC_AARCH64_MOVW_PREL_G0_NC,
+ 0,
+ 0,
+ 0},
+
+ /* Most significant bits 16-31 of signed/unsigned address/value: MOVZ */
+ {"prel_g1", 1,
+ 0, /* adr_type */
+ 0,
+ BFD_RELOC_AARCH64_MOVW_PREL_G1,
+ 0,
+ 0,
+ 0},
+
+ /* Most significant bits 16-31 of signed/unsigned address/value: MOVK */
+ {"prel_g1_nc", 1,
+ 0, /* adr_type */
+ 0,
+ BFD_RELOC_AARCH64_MOVW_PREL_G1_NC,
+ 0,
+ 0,
+ 0},
+
+ /* Most significant bits 32-47 of signed/unsigned address/value: MOVZ */
+ {"prel_g2", 1,
+ 0, /* adr_type */
+ 0,
+ BFD_RELOC_AARCH64_MOVW_PREL_G2,
+ 0,
+ 0,
+ 0},
+
+ /* Most significant bits 32-47 of signed/unsigned address/value: MOVK */
+ {"prel_g2_nc", 1,
+ 0, /* adr_type */
+ 0,
+ BFD_RELOC_AARCH64_MOVW_PREL_G2_NC,
+ 0,
+ 0,
+ 0},
+
+ /* Most significant bits 48-63 of signed/unsigned address/value: MOVZ */
+ {"prel_g3", 1,
+ 0, /* adr_type */
+ 0,
+ BFD_RELOC_AARCH64_MOVW_PREL_G3,
+ 0,
+ 0,
+ 0},
+
/* Get to the page containing GOT entry for a symbol. */
{"got", 1,
0, /* adr_type */
0,
0,
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12,
- 0,
+ BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12,
0},
/* Get tp offset for a symbol. */
0,
0,
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC,
- 0,
+ BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC,
0},
/* Most significant bits 32-47 of address/value: MOVZ. */
set_syntax_error (_("missing offset in the pre-indexed address"));
return FALSE;
}
+
operand->addr.preind = 1;
inst.reloc.exp.X_op = O_constant;
inst.reloc.exp.X_add_number = 0;
static int
parse_sys_reg (char **str, struct hash_control *sys_regs,
- int imple_defined_p, int pstatefield_p)
+ int imple_defined_p, int pstatefield_p,
+ uint32_t* flags)
{
char *p, *q;
char buf[32];
if (op0 > 3 || op1 > 7 || cn > 15 || cm > 15 || op2 > 7)
return PARSE_FAIL;
value = (op0 << 14) | (op1 << 11) | (cn << 7) | (cm << 3) | op2;
+ if (flags)
+ *flags = 0;
}
}
else
as_warn (_("system register name '%s' is deprecated and may be "
"removed in a future release"), buf);
value = o->value;
+ if (flags)
+ *flags = o->flags;
}
*str = q;
break;
/* Generate the operand string in STR. */
- aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL);
+ aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL,
+ NULL);
/* Delimiter. */
if (str[0] != '\0')
enum aarch64_opnd opd_code = (idx >= 0 ? opcode->operands[idx]
: AARCH64_OPND_NIL);
+ typedef void (*handler_t)(const char *format, ...);
+ handler_t handler = detail->non_fatal ? as_warn : as_bad;
+
switch (detail->kind)
{
case AARCH64_OPDE_NIL:
gas_assert (0);
break;
-
case AARCH64_OPDE_SYNTAX_ERROR:
case AARCH64_OPDE_RECOVERABLE:
case AARCH64_OPDE_FATAL_SYNTAX_ERROR:
if (detail->error != NULL)
{
if (idx < 0)
- as_bad (_("%s -- `%s'"), detail->error, str);
+ handler (_("%s -- `%s'"), detail->error, str);
else
- as_bad (_("%s at operand %d -- `%s'"),
- detail->error, idx + 1, str);
+ handler (_("%s at operand %d -- `%s'"),
+ detail->error, idx + 1, str);
}
else
{
gas_assert (idx >= 0);
- as_bad (_("operand %d must be %s -- `%s'"), idx + 1,
- aarch64_get_operand_desc (opd_code), str);
+ handler (_("operand %d must be %s -- `%s'"), idx + 1,
+ aarch64_get_operand_desc (opd_code), str);
}
break;
case AARCH64_OPDE_INVALID_VARIANT:
- as_bad (_("operand mismatch -- `%s'"), str);
+ handler (_("operand mismatch -- `%s'"), str);
if (verbose_error_p)
{
/* We will try to correct the erroneous instruction and also provide
break;
case AARCH64_OPDE_UNTIED_OPERAND:
- as_bad (_("operand %d must be the same register as operand 1 -- `%s'"),
- detail->index + 1, str);
+ handler (_("operand %d must be the same register as operand 1 -- `%s'"),
+ detail->index + 1, str);
break;
case AARCH64_OPDE_OUT_OF_RANGE:
if (detail->data[0] != detail->data[1])
- as_bad (_("%s out of range %d to %d at operand %d -- `%s'"),
- detail->error ? detail->error : _("immediate value"),
- detail->data[0], detail->data[1], idx + 1, str);
+ handler (_("%s out of range %d to %d at operand %d -- `%s'"),
+ detail->error ? detail->error : _("immediate value"),
+ detail->data[0], detail->data[1], idx + 1, str);
else
- as_bad (_("%s must be %d at operand %d -- `%s'"),
- detail->error ? detail->error : _("immediate value"),
- detail->data[0], idx + 1, str);
+ handler (_("%s must be %d at operand %d -- `%s'"),
+ detail->error ? detail->error : _("immediate value"),
+ detail->data[0], idx + 1, str);
break;
case AARCH64_OPDE_REG_LIST:
if (detail->data[0] == 1)
- as_bad (_("invalid number of registers in the list; "
- "only 1 register is expected at operand %d -- `%s'"),
- idx + 1, str);
+ handler (_("invalid number of registers in the list; "
+ "only 1 register is expected at operand %d -- `%s'"),
+ idx + 1, str);
else
- as_bad (_("invalid number of registers in the list; "
- "%d registers are expected at operand %d -- `%s'"),
- detail->data[0], idx + 1, str);
+ handler (_("invalid number of registers in the list; "
+ "%d registers are expected at operand %d -- `%s'"),
+ detail->data[0], idx + 1, str);
break;
case AARCH64_OPDE_UNALIGNED:
- as_bad (_("immediate value must be a multiple of "
- "%d at operand %d -- `%s'"),
- detail->data[0], idx + 1, str);
+ handler (_("immediate value must be a multiple of "
+ "%d at operand %d -- `%s'"),
+ detail->data[0], idx + 1, str);
break;
default:
When this function is called, the operand error information had
been collected for an assembly line and there will be multiple
errors in the case of multiple instruction templates; output the
- error message that most closely describes the problem. */
+ error message that most closely describes the problem.
+
+ The errors to be printed can be filtered on printing all errors
+ or only non-fatal errors. This distinction has to be made because
+ the error buffer may already be filled with fatal errors we don't want to
+ print due to the different instruction templates. */
static void
-output_operand_error_report (char *str)
+output_operand_error_report (char *str, bfd_boolean non_fatal_only)
{
int largest_error_pos;
const char *msg = NULL;
/* Only one error. */
if (head == operand_error_report.tail)
{
- DEBUG_TRACE ("single opcode entry with error kind: %s",
- operand_mismatch_kind_names[head->detail.kind]);
- output_operand_error_record (head, str);
+ /* If the only error is a non-fatal one and we don't want to print it,
+ just exit. */
+ if (!non_fatal_only || head->detail.non_fatal)
+ {
+ DEBUG_TRACE ("single opcode entry with error kind: %s",
+ operand_mismatch_kind_names[head->detail.kind]);
+ output_operand_error_record (head, str);
+ }
return;
}
largest_error_pos = -2; /* Index can be -1 which means unknown index. */
for (curr = head; curr != NULL; curr = curr->next)
{
- if (curr->detail.kind != kind)
+ /* If we don't want to print non-fatal errors then don't consider them
+ at all. */
+ if (curr->detail.kind != kind
+ || (non_fatal_only && !head->detail.non_fatal))
continue;
/* If there are multiple errors, pick up the one with the highest
mismatching operand index. In the case of multiple errors with
}
}
+ /* The way errors are collected in the back-end is a bit non-intuitive. But
+ essentially, because each operand template is tried recursively you may
+ always have errors collected from the previous tried OPND. These are
+ usually skipped if there is one successful match. However now with the
+ non-fatal errors we have to ignore those previously collected hard errors
+ when we're only interested in printing the non-fatal ones. This condition
+ prevents us from printing errors that are not appropriate, since we did
+ match a condition, but it also has warnings that it wants to print. */
+ if (non_fatal_only && !record)
+ return;
+
gas_assert (largest_error_pos != -2 && record != NULL);
DEBUG_TRACE ("Pick up error kind %s to report",
operand_mismatch_kind_names[record->detail.kind]);
= {1, 2, 4, 8, 16};
const unsigned int ele_base [5] =
{
- AARCH64_OPND_QLF_V_8B,
+ AARCH64_OPND_QLF_V_4B,
AARCH64_OPND_QLF_V_2H,
AARCH64_OPND_QLF_V_2S,
AARCH64_OPND_QLF_V_1D,
gas_assert (vectype->type >= NT_b && vectype->type <= NT_q);
if (vectype->defined & (NTA_HASINDEX | NTA_HASVARWIDTH))
- /* Vector element register. */
- return AARCH64_OPND_QLF_S_B + vectype->type;
+ {
+ /* Special case S_4B. */
+ if (vectype->type == NT_b && vectype->width == 4)
+ return AARCH64_OPND_QLF_S_4B;
+
+ /* Vector element register. */
+ return AARCH64_OPND_QLF_S_B + vectype->type;
+ }
else
{
/* Vector register. */
a vector-type dependent amount. */
shift = 0;
if (vectype->type == NT_b)
- shift = 4;
+ shift = 3;
else if (vectype->type == NT_h || vectype->type == NT_s)
shift = 2;
else if (vectype->type >= NT_d)
gas_assert (0);
offset = ele_base [vectype->type] + (vectype->width >> shift);
- gas_assert (AARCH64_OPND_QLF_V_8B <= offset
+ gas_assert (AARCH64_OPND_QLF_V_4B <= offset
&& offset <= AARCH64_OPND_QLF_V_1Q);
return offset;
}
case AARCH64_OPND_Sd:
case AARCH64_OPND_Sn:
case AARCH64_OPND_Sm:
+ case AARCH64_OPND_Va:
case AARCH64_OPND_Vd:
case AARCH64_OPND_Vn:
case AARCH64_OPND_Vm:
case AARCH64_OPND_Ed:
case AARCH64_OPND_En:
case AARCH64_OPND_Em:
+ case AARCH64_OPND_SM3_IMM2:
operand->reglane.regno = default_value;
break;
case AARCH64_OPND_UIMM3_OP1:
case AARCH64_OPND_UIMM3_OP2:
case AARCH64_OPND_IMM:
+ case AARCH64_OPND_IMM_2:
case AARCH64_OPND_WIDTH:
case AARCH64_OPND_UIMM7:
case AARCH64_OPND_NZCV:
case BFD_RELOC_AARCH64_MOVW_G0_S:
case BFD_RELOC_AARCH64_MOVW_G1_S:
case BFD_RELOC_AARCH64_MOVW_G2_S:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G3:
case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
case BFD_RELOC_AARCH64_MOVW_G0_NC:
case BFD_RELOC_AARCH64_MOVW_G0_S:
case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC:
case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
case BFD_RELOC_AARCH64_MOVW_G1_NC:
case BFD_RELOC_AARCH64_MOVW_G1_S:
case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC:
case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
case BFD_RELOC_AARCH64_MOVW_G2:
case BFD_RELOC_AARCH64_MOVW_G2_NC:
case BFD_RELOC_AARCH64_MOVW_G2_S:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC:
case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
if (is32)
shift = 32;
break;
case BFD_RELOC_AARCH64_MOVW_G3:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G3:
if (is32)
{
set_fatal_syntax_error
enum aarch64_opnd_qualifier opd0_qlf = inst.base.operands[0].qualifier;
enum aarch64_opnd_qualifier opd1_qlf = inst.base.operands[1].qualifier;
- const bfd_reloc_code_real_type reloc_ldst_lo12[3][5] = {
+ const bfd_reloc_code_real_type reloc_ldst_lo12[5][5] = {
{
BFD_RELOC_AARCH64_LDST8_LO12,
BFD_RELOC_AARCH64_LDST16_LO12,
BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC,
BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC,
BFD_RELOC_AARCH64_NONE
+ },
+ {
+ BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12,
+ BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12,
+ BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12,
+ BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12,
+ BFD_RELOC_AARCH64_NONE
+ },
+ {
+ BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC,
+ BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC,
+ BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC,
+ BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC,
+ BFD_RELOC_AARCH64_NONE
}
};
gas_assert (inst.reloc.type == BFD_RELOC_AARCH64_LDST_LO12
|| inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12
|| (inst.reloc.type
- == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC));
+ == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC)
+ || (inst.reloc.type
+ == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12)
+ || (inst.reloc.type
+ == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC));
gas_assert (inst.base.opcode->operands[1] == AARCH64_OPND_ADDR_UIMM12);
if (opd1_qlf == AARCH64_OPND_QLF_NIL)
logsz = get_logsz (aarch64_get_qualifier_esize (opd1_qlf));
if (inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12
- || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC)
+ || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC
+ || inst.reloc.type == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12
+ || inst.reloc.type == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC)
gas_assert (logsz <= 3);
else
gas_assert (logsz <= 4);
skip_whitespace (str);
if (AARCH64_CPU_HAS_FEATURE (AARCH64_FEATURE_SVE, *opcode->avariant))
- imm_reg_type = REG_TYPE_R_Z_BHSDQ_VZP;
+ imm_reg_type = REG_TYPE_R_Z_SP_BHSDQ_VZP;
else
imm_reg_type = REG_TYPE_R_Z_BHSDQ_V;
reg_type = REG_TYPE_ZN;
goto vector_reg;
+ case AARCH64_OPND_Va:
case AARCH64_OPND_Vd:
case AARCH64_OPND_Vn:
case AARCH64_OPND_Vm:
case AARCH64_OPND_Ed:
case AARCH64_OPND_En:
case AARCH64_OPND_Em:
+ case AARCH64_OPND_SM3_IMM2:
reg_type = REG_TYPE_VN;
vector_reg_index:
val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
case AARCH64_OPND_UIMM3_OP2:
case AARCH64_OPND_IMM_VLSL:
case AARCH64_OPND_IMM:
+ case AARCH64_OPND_IMM_2:
case AARCH64_OPND_WIDTH:
case AARCH64_OPND_SVE_INV_LIMM:
case AARCH64_OPND_SVE_LIMM:
break;
case AARCH64_OPND_IDX:
+ case AARCH64_OPND_MASK:
case AARCH64_OPND_BIT_NUM:
case AARCH64_OPND_IMMR:
case AARCH64_OPND_IMMS:
break;
case AARCH64_OPND_ADDR_SIMM10:
+ case AARCH64_OPND_ADDR_OFFSET:
po_misc_or_fail (parse_address (&str, info));
if (info->addr.pcrel || info->addr.offset.is_reg
|| !info->addr.preind || info->addr.postind)
|| (inst.reloc.type
== BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12)
|| (inst.reloc.type
- == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC))
+ == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC)
+ || (inst.reloc.type
+ == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12)
+ || (inst.reloc.type
+ == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC))
inst.reloc.type = ldst_lo12_determine_real_reloc_type ();
/* Leave qualifier to be determined by libopcodes. */
break;
info->addr.offset.imm = inst.reloc.exp.X_add_number;
break;
+ case AARCH64_OPND_SVE_ADDR_R:
+ /* [<Xn|SP>{, <R><m>}]
+ but recognizing SVE registers. */
+ po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+ &offset_qualifier));
+ if (offset_qualifier == AARCH64_OPND_QLF_NIL)
+ {
+ offset_qualifier = AARCH64_OPND_QLF_X;
+ info->addr.offset.is_reg = 1;
+ info->addr.offset.regno = 31;
+ }
+ else if (base_qualifier != AARCH64_OPND_QLF_X
+ || offset_qualifier != AARCH64_OPND_QLF_X)
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ goto regoff_addr;
+
case AARCH64_OPND_SVE_ADDR_RR:
case AARCH64_OPND_SVE_ADDR_RR_LSL1:
case AARCH64_OPND_SVE_ADDR_RR_LSL2:
goto regoff_addr;
case AARCH64_OPND_SYSREG:
- if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0))
- == PARSE_FAIL)
- {
- set_syntax_error (_("unknown or missing system register name"));
- goto failure;
- }
- inst.base.operands[i].sysreg = val;
- break;
+ {
+ uint32_t sysreg_flags;
+ if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0,
+ &sysreg_flags)) == PARSE_FAIL)
+ {
+ set_syntax_error (_("unknown or missing system register name"));
+ goto failure;
+ }
+ inst.base.operands[i].sysreg.value = val;
+ inst.base.operands[i].sysreg.flags = sysreg_flags;
+ break;
+ }
case AARCH64_OPND_PSTATEFIELD:
- if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1))
+ if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1, NULL))
== PARSE_FAIL)
{
set_syntax_error (_("unknown or missing PSTATE field name"));
aarch64_insn *code)
{
aarch64_operand_error error_info;
+ memset (&error_info, '\0', sizeof (error_info));
error_info.kind = AARCH64_OPDE_NIL;
- if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info))
+ if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info)
+ && !error_info.non_fatal)
return TRUE;
- else
- {
- gas_assert (error_info.kind != AARCH64_OPDE_NIL);
- record_operand_error_info (opcode, &error_info);
- return FALSE;
- }
+
+ gas_assert (error_info.kind != AARCH64_OPDE_NIL);
+ record_operand_error_info (opcode, &error_info);
+ return error_info.non_fatal;
}
#ifdef DEBUG_AARCH64
memcpy (copy, &inst.base, sizeof (struct aarch64_inst));
output_inst (copy);
}
+
+ /* Issue non-fatal messages if any. */
+ output_operand_error_report (str, TRUE);
return;
}
while (template != NULL);
/* Issue the error messages if any. */
- output_operand_error_report (str);
+ output_operand_error_report (str, FALSE);
}
/* Various frobbings of labels and their addresses. */
REGSET31 (w, R_32), REGSET31 (W, R_32),
REGDEF_ALIAS (ip0, 16, R_64), REGDEF_ALIAS (IP0, 16, R_64),
- REGDEF_ALIAS (ip1, 17, R_64), REGDEF_ALIAS (IP1, 16, R_64),
+ REGDEF_ALIAS (ip1, 17, R_64), REGDEF_ALIAS (IP1, 17, R_64),
REGDEF_ALIAS (fp, 29, R_64), REGDEF_ALIAS (FP, 29, R_64),
REGDEF_ALIAS (lr, 30, R_64), REGDEF_ALIAS (LR, 30, R_64),
REGDEF (wsp, 31, SP_32), REGDEF (WSP, 31, SP_32),
case BFD_RELOC_AARCH64_MOVW_G0_NC:
case BFD_RELOC_AARCH64_MOVW_G0_S:
case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC:
scale = 0;
goto movw_common;
case BFD_RELOC_AARCH64_MOVW_G1:
case BFD_RELOC_AARCH64_MOVW_G1_NC:
case BFD_RELOC_AARCH64_MOVW_G1_S:
case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC:
scale = 16;
goto movw_common;
case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
case BFD_RELOC_AARCH64_MOVW_G2:
case BFD_RELOC_AARCH64_MOVW_G2_NC:
case BFD_RELOC_AARCH64_MOVW_G2_S:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC:
scale = 32;
goto movw_common;
case BFD_RELOC_AARCH64_MOVW_G3:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G3:
scale = 48;
movw_common:
if (fixP->fx_done || !seg->use_rela_p)
case BFD_RELOC_AARCH64_MOVW_G0_S:
case BFD_RELOC_AARCH64_MOVW_G1_S:
case BFD_RELOC_AARCH64_MOVW_G2_S:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2:
/* NOTE: We can only come here with movz or movn. */
if (signed_overflow (value, scale + 16))
as_bad_where (fixP->fx_file, fixP->fx_line,
case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
+ case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
+ case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO
| AARCH64_FEATURE_RDMA),
"Qualcomm QDF24XX"},
- {"saphira", AARCH64_FEATURE (AARCH64_ARCH_V8_3,
+ {"saphira", AARCH64_FEATURE (AARCH64_ARCH_V8_4,
AARCH64_FEATURE_CRYPTO | AARCH64_FEATURE_PROFILE),
"Qualcomm Saphira"},
{"thunderx", AARCH64_FEATURE (AARCH64_ARCH_V8,
{"armv8.1-a", AARCH64_ARCH_V8_1},
{"armv8.2-a", AARCH64_ARCH_V8_2},
{"armv8.3-a", AARCH64_ARCH_V8_3},
+ {"armv8.4-a", AARCH64_ARCH_V8_4},
{NULL, AARCH64_ARCH_NONE}
};
static const struct aarch64_option_cpu_value_table aarch64_features[] = {
{"crc", AARCH64_FEATURE (AARCH64_FEATURE_CRC, 0),
AARCH64_ARCH_NONE},
- {"crypto", AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO, 0),
+ {"crypto", AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO
+ | AARCH64_FEATURE_AES
+ | AARCH64_FEATURE_SHA2, 0),
AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
{"fp", AARCH64_FEATURE (AARCH64_FEATURE_FP, 0),
AARCH64_ARCH_NONE},
AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
{"fp16", AARCH64_FEATURE (AARCH64_FEATURE_F16, 0),
AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
+ {"fp16fml", AARCH64_FEATURE (AARCH64_FEATURE_F16_FML, 0),
+ AARCH64_FEATURE (AARCH64_FEATURE_FP
+ | AARCH64_FEATURE_F16, 0)},
{"profile", AARCH64_FEATURE (AARCH64_FEATURE_PROFILE, 0),
AARCH64_ARCH_NONE},
{"sve", AARCH64_FEATURE (AARCH64_FEATURE_SVE, 0),
AARCH64_ARCH_NONE},
{"dotprod", AARCH64_FEATURE (AARCH64_FEATURE_DOTPROD, 0),
AARCH64_ARCH_NONE},
+ {"sha2", AARCH64_FEATURE (AARCH64_FEATURE_SHA2, 0),
+ AARCH64_ARCH_NONE},
+ {"aes", AARCH64_FEATURE (AARCH64_FEATURE_AES, 0),
+ AARCH64_ARCH_NONE},
+ {"sm4", AARCH64_FEATURE (AARCH64_FEATURE_SM4, 0),
+ AARCH64_ARCH_NONE},
+ {"sha3", AARCH64_FEATURE (AARCH64_FEATURE_SHA2
+ | AARCH64_FEATURE_SHA3, 0),
+ AARCH64_ARCH_NONE},
{NULL, AARCH64_ARCH_NONE, AARCH64_ARCH_NONE},
};