/* Constants for known architecture features. */
static const aarch64_feature_set cpu_default = CPU_DEFAULT;
+/* Currently active instruction sequence. */
+static aarch64_instr_sequence *insn_sequence = NULL;
+
#ifdef OBJ_ELF
/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
static symbolS *GOT_symbol;
static bfd_boolean parse_operands (char *, const aarch64_opcode *);
static bfd_boolean programmer_friendly_fixup (aarch64_instruction *);
+#ifdef OBJ_ELF
+# define now_instr_sequence seg_info \
+ (now_seg)->tc_segment_info_data.insn_sequence
+#else
+static struct aarch64_instr_sequence now_instr_sequence;
+#endif
+
/* Diagnostics inline function utilities.
These are lightweight utilities which should only be called by parse_operands
static struct hash_control *aarch64_sys_regs_dc_hsh;
static struct hash_control *aarch64_sys_regs_at_hsh;
static struct hash_control *aarch64_sys_regs_tlbi_hsh;
+static struct hash_control *aarch64_sys_regs_sr_hsh;
static struct hash_control *aarch64_reg_hsh;
static struct hash_control *aarch64_barrier_opt_hsh;
static struct hash_control *aarch64_nzcv_hsh;
return 0;
}
+/* Parse an operand for BTI. Set *HINT_OPT to the hint-option record
+ return 0 if successful. Otherwise return PARSE_FAIL. */
+
+static int
+parse_bti_operand (char **str,
+ const struct aarch64_name_value_pair ** hint_opt)
+{
+ char *p, *q;
+ const struct aarch64_name_value_pair *o;
+
+ p = q = *str;
+ while (ISALPHA (*q))
+ q++;
+
+ o = hash_find_n (aarch64_hint_opt_hsh, p, q - p);
+ if (!o)
+ {
+ set_fatal_syntax_error
+ ( _("unknown option to BTI"));
+ return PARSE_FAIL;
+ }
+
+ switch (o->value)
+ {
+ /* Valid BTI operands. */
+ case HINT_OPD_C:
+ case HINT_OPD_J:
+ case HINT_OPD_JC:
+ break;
+
+ default:
+ set_syntax_error
+ (_("unknown option to BTI"));
+ return PARSE_FAIL;
+ }
+
+ *str = q;
+ *hint_opt = o;
+ return 0;
+}
+
/* Parse a system register or a PSTATE field name for an MSR/MRS instruction.
Returns the encoding for the option, or PARSE_FAIL.
&& programmer_friendly_fixup (&inst);
gas_assert (result);
result = aarch64_opcode_encode (opcode, inst_base, &inst_base->value,
- NULL, NULL);
+ NULL, NULL, insn_sequence);
gas_assert (!result);
/* Find the most matched qualifier sequence. */
{
gas_assert (curr->detail.kind != AARCH64_OPDE_NIL);
DEBUG_TRACE ("\t%s", operand_mismatch_kind_names[curr->detail.kind]);
- if (operand_error_higher_severity_p (curr->detail.kind, kind))
+ if (operand_error_higher_severity_p (curr->detail.kind, kind)
+ && (!non_fatal_only || (non_fatal_only && curr->detail.non_fatal)))
kind = curr->detail.kind;
}
- gas_assert (kind != AARCH64_OPDE_NIL);
+
+ gas_assert (kind != AARCH64_OPDE_NIL || non_fatal_only);
/* Pick up one of errors of KIND to report. */
largest_error_pos = -2; /* Index can be -1 which means unknown index. */
/* 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))
+ || (non_fatal_only && !curr->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
case AARCH64_OPND_BARRIER_ISB:
operand->barrier = aarch64_barrier_options + default_value;
+ break;
+
+ case AARCH64_OPND_BTI_TARGET:
+ operand->hint_option = aarch64_hint_options + default_value;
+ break;
default:
break;
inst.base.operands[i].sysins_op =
parse_sys_ins_reg (&str, aarch64_sys_regs_ic_hsh);
goto sys_reg_ins;
+
case AARCH64_OPND_SYSREG_DC:
inst.base.operands[i].sysins_op =
parse_sys_ins_reg (&str, aarch64_sys_regs_dc_hsh);
goto sys_reg_ins;
+
case AARCH64_OPND_SYSREG_AT:
inst.base.operands[i].sysins_op =
parse_sys_ins_reg (&str, aarch64_sys_regs_at_hsh);
goto sys_reg_ins;
+
+ case AARCH64_OPND_SYSREG_SR:
+ inst.base.operands[i].sysins_op =
+ parse_sys_ins_reg (&str, aarch64_sys_regs_sr_hsh);
+ goto sys_reg_ins;
+
case AARCH64_OPND_SYSREG_TLBI:
inst.base.operands[i].sysins_op =
parse_sys_ins_reg (&str, aarch64_sys_regs_tlbi_hsh);
goto failure;
break;
+ case AARCH64_OPND_BTI_TARGET:
+ val = parse_bti_operand (&str, &(info->hint_option));
+ if (val == PARSE_FAIL)
+ goto failure;
+ break;
+
default:
as_fatal (_("unhandled operand code %d"), operands[i]);
}
}
}
+static void
+force_automatic_sequence_close (void)
+{
+ if (now_instr_sequence.instr)
+ {
+ as_warn (_("previous `%s' sequence has not been closed"),
+ now_instr_sequence.instr->opcode->name);
+ init_insn_sequence (NULL, &now_instr_sequence);
+ }
+}
+
/* A wrapper function to interface with libopcodes on encoding and
record the error message if there is any.
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, insn_sequence)
&& !error_info.non_fatal)
return TRUE;
S_SET_SEGMENT (last_label_seen, now_seg);
}
+ /* Update the current insn_sequence from the segment. */
+ insn_sequence = &seg_info (now_seg)->tc_segment_info_data.insn_sequence;
+
inst.reloc.type = BFD_RELOC_UNUSED;
DEBUG_TRACE ("\n\n");
dwarf2_emit_label (sym);
}
+void
+aarch64_frob_section (asection *sec ATTRIBUTE_UNUSED)
+{
+ /* Check to see if we have a block to close. */
+ force_automatic_sequence_close ();
+}
+
int
aarch64_data_in_code (void)
{
DEBUG_TRACE ("Found LDURB entry to encode programmer-friendly LDRB");
- if (!aarch64_opcode_encode (instr->opcode, instr, &instr->value, NULL, NULL))
+ if (!aarch64_opcode_encode (instr->opcode, instr, &instr->value, NULL, NULL,
+ insn_sequence))
return FALSE;
return TRUE;
opcode = aarch64_get_opcode (OP_MOV_IMM_WIDE);
aarch64_replace_opcode (instr, opcode);
if (aarch64_opcode_encode (instr->opcode, instr,
- &instr->value, NULL, NULL))
+ &instr->value, NULL, NULL, insn_sequence))
{
put_aarch64_insn (buf, instr->value);
return;
opcode = aarch64_get_opcode (OP_MOV_IMM_WIDEN);
aarch64_replace_opcode (instr, opcode);
if (aarch64_opcode_encode (instr->opcode, instr,
- &instr->value, NULL, NULL))
+ &instr->value, NULL, NULL, insn_sequence))
{
put_aarch64_insn (buf, instr->value);
return;
opcode = aarch64_get_opcode (OP_MOV_IMM_LOG);
aarch64_replace_opcode (instr, opcode);
if (aarch64_opcode_encode (instr->opcode, instr,
- &instr->value, NULL, NULL))
+ &instr->value, NULL, NULL, insn_sequence))
{
put_aarch64_insn (buf, instr->value);
return;
idx = aarch64_operand_index (new_inst->opcode->operands, opnd);
new_inst->operands[idx].imm.value = value;
if (aarch64_opcode_encode (new_inst->opcode, new_inst,
- &new_inst->value, NULL, NULL))
+ &new_inst->value, NULL, NULL, insn_sequence))
put_aarch64_insn (buf, new_inst->value);
else
as_bad_where (fixP->fx_file, fixP->fx_line,
/* Encode/fix-up. */
if (aarch64_opcode_encode (new_inst->opcode, new_inst,
- &new_inst->value, NULL, NULL))
+ &new_inst->value, NULL, NULL, insn_sequence))
{
put_aarch64_insn (buf, new_inst->value);
break;
|| (aarch64_sys_regs_dc_hsh = hash_new ()) == NULL
|| (aarch64_sys_regs_at_hsh = hash_new ()) == NULL
|| (aarch64_sys_regs_tlbi_hsh = hash_new ()) == NULL
+ || (aarch64_sys_regs_sr_hsh = hash_new ()) == NULL
|| (aarch64_reg_hsh = hash_new ()) == NULL
|| (aarch64_barrier_opt_hsh = hash_new ()) == NULL
|| (aarch64_nzcv_hsh = hash_new ()) == NULL
aarch64_sys_regs_tlbi[i].name,
(void *) (aarch64_sys_regs_tlbi + i));
+ for (i = 0; aarch64_sys_regs_sr[i].name != NULL; i++)
+ checked_hash_insert (aarch64_sys_regs_sr_hsh,
+ aarch64_sys_regs_sr[i].name,
+ (void *) (aarch64_sys_regs_sr + i));
+
for (i = 0; i < ARRAY_SIZE (reg_names); i++)
checked_hash_insert (aarch64_reg_hsh, reg_names[i].name,
(void *) (reg_names + i));
{"armv8.2-a", AARCH64_ARCH_V8_2},
{"armv8.3-a", AARCH64_ARCH_V8_3},
{"armv8.4-a", AARCH64_ARCH_V8_4},
+ {"armv8.5-a", AARCH64_ARCH_V8_5},
{NULL, AARCH64_ARCH_NONE}
};
AARCH64_ARCH_NONE},
{"sha2", AARCH64_FEATURE (AARCH64_FEATURE_SHA2, 0),
AARCH64_ARCH_NONE},
+ {"sb", AARCH64_FEATURE (AARCH64_FEATURE_SB, 0),
+ AARCH64_ARCH_NONE},
+ {"predres", AARCH64_FEATURE (AARCH64_FEATURE_PREDRES, 0),
+ AARCH64_ARCH_NONE},
{"aes", AARCH64_FEATURE (AARCH64_FEATURE_AES, 0),
AARCH64_ARCH_NONE},
{"sm4", AARCH64_FEATURE (AARCH64_FEATURE_SM4, 0),
{"sha3", AARCH64_FEATURE (AARCH64_FEATURE_SHA2
| AARCH64_FEATURE_SHA3, 0),
AARCH64_ARCH_NONE},
+ {"rng", AARCH64_FEATURE (AARCH64_FEATURE_RNG, 0),
+ AARCH64_ARCH_NONE},
+ {"ssbs", AARCH64_FEATURE (AARCH64_FEATURE_SSBS, 0),
+ AARCH64_ARCH_NONE},
+ {"memtag", AARCH64_FEATURE (AARCH64_FEATURE_MEMTAG, 0),
+ AARCH64_ARCH_NONE},
{NULL, AARCH64_ARCH_NONE, AARCH64_ARCH_NONE},
};