+2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
+
+ * cpu-aarch64.c (bfd_is_aarch64_special_symbol_name): Add
+ capability mapping symbol.
+ * elfnn-aarch64.c (elfNN_aarch64_output_map_sym,
+ is_aarch64_mapping_symbol): Likewise.
+
2020-10-16 Nelson Chu <nelson.chu@sifive.com>
* elfnn-riscv.c (riscv_elf_link_hash_table): Add last_iplt_index.
{
if (!name || name[0] != '$')
return FALSE;
- if (name[1] == 'x' || name[1] == 'd')
+ if (name[1] == 'x' || name[1] == 'd' || name[1] == 'c')
type &= BFD_AARCH64_SPECIAL_SYM_TYPE_MAP;
else if (name[1] == 'm' || name[1] == 'f' || name[1] == 'p')
type &= BFD_AARCH64_SPECIAL_SYM_TYPE_TAG;
elfNN_aarch64_output_map_sym (output_arch_syminfo *osi,
enum map_symbol_type type, bfd_vma offset)
{
- static const char *names[2] = { "$x", "$d" };
+ static const char *names[3] = { "$x", "$d", "$c" };
Elf_Internal_Sym sym;
sym.st_value = (osi->sec->output_section->vma
the mapping symbols could have acquired a prefix.
We do not support this here, since such symbols no
longer conform to the ARM ELF ABI. */
- && (name[1] == 'd' || name[1] == 'x')
+ && (name[1] == 'd' || name[1] == 'x' || name[1] == 'c')
&& (name[2] == 0 || name[2] == '.');
/* FIXME: Strictly speaking the symbol is only a valid mapping symbol if
any characters that follow the period are legal characters for the body
+2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
+
+ * config/tc-aarch64.h (mstate): Add MAP_C64.
+ * config/tc-aarch64.c (make_mapping_symbol): Add capability
+ mapping symbol.
+ (MAP_CUR_INSN): New macro.
+ (mapping_state, s_aarch64_inst, md_assemble,
+ aarch64_handle_align, aarch64_init_frag): Use it.
+ (output_operand_error_record, do_encode,
+ try_to_encode_as_unscaled_ldst, fix_mov_imm_insn, fix_insn):
+ Pass CPU_VARIANT to AARCH64_OPCODE_ENCODE.
+ * doc/c-aarch64.texi: Document $c.
+
2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
* config/tc-aarch64.c (AARCH64_REG_TYPES,
#define END_OF_INSN '\0'
+#define MAP_CUR_INSN (AARCH64_CPU_HAS_FEATURE (cpu_variant, \
+ AARCH64_FEATURE_C64) \
+ ? MAP_C64 : MAP_INSN)
+
static aarch64_feature_set cpu_variant;
/* Variables that we set while parsing command-line options. Once all
symname = "$x";
type = BSF_NO_FLAGS;
break;
+ case MAP_C64:
+ symname = "$c";
+ type = BSF_NO_FLAGS;
+ break;
default:
abort ();
}
{
enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
- if (state == MAP_INSN)
+ if (state == MAP_CUR_INSN)
/* AArch64 instructions require 4-byte alignment. When emitting
instructions into any section, record the appropriate section
alignment. */
/* Emit MAP_DATA within executable section in order. Otherwise, it will be
evaluated later in the next else. */
return;
- else if (TRANSITION (MAP_UNDEFINED, MAP_INSN))
+ else if (TRANSITION (MAP_UNDEFINED, MAP_CUR_INSN))
{
/* Only add the symbol if the offset is > 0:
if we're at the first frag, check it's size > 0;
/* Sections are assumed to start aligned. In executable section, there is no
MAP_DATA symbol pending. So we only align the address during
- MAP_DATA --> MAP_INSN transition.
+ MAP_DATA --> MAP_CUR_INSN transition.
For other sections, this is not guaranteed. */
enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
if (!need_pass_2 && subseg_text_p (now_seg) && mapstate == MAP_DATA)
frag_align_code (2, 0);
#ifdef OBJ_ELF
- mapping_state (MAP_INSN);
+ mapping_state (MAP_CUR_INSN);
#endif
do
result = parse_operands (str + len, opcode)
&& programmer_friendly_fixup (&inst);
gas_assert (result);
- result = aarch64_opcode_encode (opcode, inst_base, &inst_base->value,
- NULL, NULL, insn_sequence);
+ result = aarch64_opcode_encode (cpu_variant, opcode, inst_base,
+ &inst_base->value, NULL, NULL,
+ insn_sequence);
gas_assert (!result);
/* Find the most matched qualifier sequence. */
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, insn_sequence)
+ if (aarch64_opcode_encode (cpu_variant, opcode, instr, code, NULL,
+ &error_info, insn_sequence)
&& !error_info.non_fatal)
return TRUE;
/* Sections are assumed to start aligned. In executable section, there is no
MAP_DATA symbol pending. So we only align the address during
- MAP_DATA --> MAP_INSN transition.
+ MAP_DATA --> MAP_CUR_INSN transition.
For other sections, this is not guaranteed. */
enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
if (!need_pass_2 && subseg_text_p (now_seg) && mapstate == MAP_DATA)
dump_opcode_operands (opcode);
#endif /* DEBUG_AARCH64 */
- mapping_state (MAP_INSN);
+ mapping_state (MAP_CUR_INSN);
inst_base = &inst.base;
inst_base->opcode = opcode;
if (fix)
{
#ifdef OBJ_ELF
- insert_data_mapping_symbol (MAP_INSN, fragP->fr_fix, fragP, fix);
+ insert_data_mapping_symbol (MAP_CUR_INSN, fragP->fr_fix, fragP, fix);
#endif
memset (p, 0, fix);
p += fix;
case rs_align:
/* PR 20364: We can get alignment frags in code sections,
so do not just assume that we should use the MAP_DATA state. */
- mapping_state_2 (subseg_text_p (now_seg) ? MAP_INSN : MAP_DATA, max_chars);
+ mapping_state_2 (subseg_text_p (now_seg) ? MAP_CUR_INSN : MAP_DATA, max_chars);
break;
case rs_align_code:
- mapping_state_2 (MAP_INSN, max_chars);
+ mapping_state_2 (MAP_CUR_INSN, max_chars);
break;
default:
break;
DEBUG_TRACE ("Found LDURB entry to encode programmer-friendly LDRB");
- if (!aarch64_opcode_encode (instr->opcode, instr, &instr->value, NULL, NULL,
- insn_sequence))
+ if (!aarch64_opcode_encode (cpu_variant, instr->opcode, instr, &instr->value,
+ NULL, NULL, insn_sequence))
return FALSE;
return TRUE;
/* Try the MOVZ alias. */
opcode = aarch64_get_opcode (OP_MOV_IMM_WIDE);
aarch64_replace_opcode (instr, opcode);
- if (aarch64_opcode_encode (instr->opcode, instr,
+ if (aarch64_opcode_encode (cpu_variant, instr->opcode, instr,
&instr->value, NULL, NULL, insn_sequence))
{
put_aarch64_insn (buf, instr->value);
/* Try the MOVK alias. */
opcode = aarch64_get_opcode (OP_MOV_IMM_WIDEN);
aarch64_replace_opcode (instr, opcode);
- if (aarch64_opcode_encode (instr->opcode, instr,
+ if (aarch64_opcode_encode (cpu_variant, instr->opcode, instr,
&instr->value, NULL, NULL, insn_sequence))
{
put_aarch64_insn (buf, instr->value);
/* Try the ORR alias. */
opcode = aarch64_get_opcode (OP_MOV_IMM_LOG);
aarch64_replace_opcode (instr, opcode);
- if (aarch64_opcode_encode (instr->opcode, instr,
+ if (aarch64_opcode_encode (cpu_variant, instr->opcode, instr,
&instr->value, NULL, NULL, insn_sequence))
{
put_aarch64_insn (buf, instr->value);
gas_assert (new_inst != NULL);
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,
+ if (aarch64_opcode_encode (cpu_variant, new_inst->opcode, new_inst,
&new_inst->value, NULL, NULL, insn_sequence))
put_aarch64_insn (buf, new_inst->value);
else
new_inst->operands[idx].addr.offset.imm = value;
/* Encode/fix-up. */
- if (aarch64_opcode_encode (new_inst->opcode, new_inst,
+ if (aarch64_opcode_encode (cpu_variant, new_inst->opcode, new_inst,
&new_inst->value, NULL, NULL, insn_sequence))
{
put_aarch64_insn (buf, new_inst->value);
MAP_UNDEFINED = 0, /* Must be zero, for seginfo in new sections. */
MAP_DATA,
MAP_INSN,
+ MAP_C64,
};
void mapping_state (enum mstate);
@item $x
At the start of a region of code containing AArch64 instructions.
+@cindex @code{$c}
+@item $c
+At the start of a region of code containing C64 instructions (as oppposed to
+standard A64 or A64C instructions).
+
@cindex @code{$d}
@item $d
At the start of a region of data.
+2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
+
+ * opcode/aarch64.h (aarch64_opcode_encode): Add cpu variant
+ argument.
+
2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
* opcode/aarch64.h (AARCH64_FEATURE_A64C,
/* Encoding entrypoint. */
extern int
-aarch64_opcode_encode (const aarch64_opcode *, const aarch64_inst *,
- aarch64_insn *, aarch64_opnd_qualifier_t *,
- aarch64_operand_error *, aarch64_instr_sequence *);
+aarch64_opcode_encode (aarch64_feature_set, const aarch64_opcode *,
+ const aarch64_inst *, aarch64_insn *,
+ aarch64_opnd_qualifier_t *, aarch64_operand_error *,
+ aarch64_instr_sequence *);
extern const aarch64_opcode *
aarch64_replace_opcode (struct aarch64_inst *,
+2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
+
+ * aarch64-asm.c (aarch64_opcode_encode): Add CPU variant
+ argument.
+ * aarch64-dis.c (map_type): Add MAP_C64.
+ (MAYBE_C64): New macro.
+ (determine_disassembling_preference, print_operands): Use it.
+ (aarch64_symbol_is_valid): Test for $c.
+ (get_sym_code_type): Recognise MAP_C64.
+ (select_aarch64_variant): Clear AARCH64_FEATURE_C64.
+ (determine_disassembling_preference, aarch64_opcode_decode):
+ Adjust calls to aarch64_match_operands_constraint.
+ * aarch64-opc.c (get_altbase_reg_name, get_base_reg_name): New
+ functions.
+ (aarch64_print_operand): Use them.
+ (aarch64_match_operands_constraint): Likewise.
+ * aarch64-opc.h (aarch64_match_operands_constraint): Add CPU
+ variant argument.
+
2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
* aarch64-opc.c (fields): New capability register fields.
matched operand qualifier sequence in *QLF_SEQ. */
bfd_boolean
-aarch64_opcode_encode (const aarch64_opcode *opcode,
+aarch64_opcode_encode (aarch64_feature_set features,
+ const aarch64_opcode *opcode,
const aarch64_inst *inst_ori, aarch64_insn *code,
aarch64_opnd_qualifier_t *qlf_seq,
aarch64_operand_error *mismatch_detail,
/* Constrain the operands.
After passing this, the encoding is guaranteed to succeed. */
- if (aarch64_match_operands_constraint (inst, mismatch_detail) == 0)
+ if (aarch64_match_operands_constraint (features, inst, mismatch_detail) == 0)
{
DEBUG_TRACE ("FAIL since operand constraint not met");
return 0;
enum map_type
{
MAP_INSN,
- MAP_DATA
+ MAP_DATA,
+ MAP_C64
};
static aarch64_feature_set arch_variant; /* See select_aarch64_variant. */
static bfd_vma last_stop_offset = 0;
static bfd_vma last_mapping_addr = 0;
+#define MAYBE_C64 (last_type == MAP_C64 ? AARCH64_FEATURE_C64 : 0)
+
/* Other options */
static int no_aliases = 0; /* If set disassemble as most general inst. */
\fstatic int no_notes = 1; /* If set do not print disassemble notes in the
if (convert_to_alias (©, alias) == 1)
{
aarch64_replace_opcode (©, alias);
- assert (aarch64_match_operands_constraint (©, NULL));
+ assert (aarch64_match_operands_constraint (MAYBE_C64, ©,
+ NULL));
DEBUG_TRACE ("succeed with %s via conversion", alias->name);
memcpy (inst, ©, sizeof (aarch64_inst));
return;
}
/* Match the qualifiers. */
- if (aarch64_match_operands_constraint (inst, NULL) == 1)
+ if (aarch64_match_operands_constraint (MAYBE_C64, inst, NULL) == 1)
{
/* Arriving here, the CODE has been determined as a valid instruction
of OPCODE and *INST has been filled with information of this OPCODE
/* Generate the operand string in STR. */
aarch64_print_operand (str, sizeof (str), pc, opcode, opnds, i, &pcrel_p,
- &info->target, ¬es, arch_variant);
+ &info->target, ¬es, arch_variant | MAYBE_C64);
/* Print the delimiter (taking account of omitted operand(s)). */
if (str[0] != '\0')
return name
&& (name[0] != '$'
- || (name[1] != 'x' && name[1] != 'd')
+ || (name[1] != 'x' && name[1] != 'd' && name[1] != 'c')
|| (name[2] != '\0' && name[2] != '.'));
}
type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
- /* If the symbol has function type then use that. */
+ /* If the symbol has function type then use that. Set mapping symbol as
+ MAP_INSN only if transitioning from MAP_DATA. We do this to conserve any
+ previous MAP_C64 type. */
if (type == STT_FUNC)
{
- *map_type = MAP_INSN;
+ *map_type = *map_type == MAP_DATA ? MAP_INSN : *map_type;
return TRUE;
}
/* Check for mapping symbols. */
name = bfd_asymbol_name(info->symtab[n]);
if (name[0] == '$'
- && (name[1] == 'x' || name[1] == 'd')
+ && (name[1] == 'x' || name[1] == 'd' || name[1] == 'c')
&& (name[2] == '\0' || name[2] == '.'))
{
- *map_type = (name[1] == 'x' ? MAP_INSN : MAP_DATA);
+ switch (name[1])
+ {
+ case 'd':
+ *map_type = MAP_DATA;
+ break;
+ case 'x':
+ *map_type = MAP_INSN;
+ break;
+ case 'c':
+ *map_type = MAP_C64;
+ break;
+ default:
+ abort ();
+ }
return TRUE;
}
for the chosen architecture variant.
Currently we only restrict disassembly for Armv8-R and otherwise enable all
- non-R-profile features. */
+ non-R-profile features with the exception of C64, which is set based on
+ mapping symbols. */
static void
select_aarch64_variant (unsigned mach)
{
arch_variant = AARCH64_ARCH_V8_R;
break;
default:
- arch_variant = AARCH64_ANY & ~(AARCH64_FEATURE_V8_R);
+ arch_variant = AARCH64_ANY & ~(AARCH64_FEATURE_V8_R
+ | AARCH64_FEATURE_C64);
}
}
HEX file or similar. */
enum map_type type = MAP_DATA;
if ((info->section && info->section->flags & SEC_CODE) || !info->section)
- type = MAP_INSN;
+ type = last_type == MAP_C64 ? MAP_C64 : MAP_INSN;
/* First check the full symtab for a mapping symbol, even if there
are no usable non-mapping symbols for this address. */
Un-determined operand qualifiers may get established during the process. */
int
-aarch64_match_operands_constraint (aarch64_inst *inst,
+aarch64_match_operands_constraint (aarch64_feature_set features
+ ATTRIBUTE_UNUSED, aarch64_inst *inst,
aarch64_operand_error *mismatch_detail)
{
int i;
continue;
}
if (operand_general_constraint_met_p (inst->operands, i, type,
- inst->opcode, mismatch_detail) == 0)
+ inst->opcode,
+ mismatch_detail) == 0)
{
DEBUG_TRACE ("FAIL on operand %d", i);
return 0;
return int_reg[has_zr][2][regno];
}
+static inline const char *
+get_base_reg_name (aarch64_feature_set features, int regno, int sp_reg_p)
+{
+ if (AARCH64_CPU_HAS_FEATURE(features, AARCH64_FEATURE_C64))
+ return get_cap_reg_name (regno, sp_reg_p);
+ else
+ return get_64bit_int_reg_name (regno, sp_reg_p);
+}
+
/* Get the name of the integer offset register in OPND, using the shift type
to decide whether it's a word or doubleword. */
case AARCH64_OPND_ADDR_SIMPLE:
case AARCH64_OPND_SIMD_ADDR_SIMPLE:
case AARCH64_OPND_SIMD_ADDR_POST:
- name = get_64bit_int_reg_name (opnd->addr.base_regno, 1);
+ name = get_base_reg_name (features, opnd->addr.base_regno, 1);
if (opnd->type == AARCH64_OPND_SIMD_ADDR_POST)
{
if (opnd->addr.offset.is_reg)
case AARCH64_OPND_SVE_ADDR_RX_LSL2:
case AARCH64_OPND_SVE_ADDR_RX_LSL3:
print_register_offset_address
- (buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1),
+ (buf, size, opnd,
+ get_base_reg_name (features, opnd->addr.base_regno, 1),
get_offset_int_reg_name (opnd));
break;
case AARCH64_OPND_SVE_ADDR_RI_U6x4:
case AARCH64_OPND_SVE_ADDR_RI_U6x8:
print_immediate_offset_address
- (buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1));
+ (buf, size, opnd,
+ get_base_reg_name (features, opnd->addr.base_regno, 1));
break;
case AARCH64_OPND_SVE_ADDR_ZI_U5:
break;
case AARCH64_OPND_ADDR_UIMM12:
- name = get_64bit_int_reg_name (opnd->addr.base_regno, 1);
+ name = get_base_reg_name (features, opnd->addr.base_regno, 1);
if (opnd->addr.offset.imm)
snprintf (buf, size, "[%s, #%d]", name, opnd->addr.offset.imm);
else
\f
/* Operand qualifier and operand constraint checking. */
-int aarch64_match_operands_constraint (aarch64_inst *,
+int aarch64_match_operands_constraint (aarch64_feature_set, aarch64_inst *,
aarch64_operand_error *);
/* Operand qualifier related functions. */