X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=opcodes%2Faarch64-dis.c;h=6567880efbaaeea5e1f2aa026df99059e9bb7471;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=fe3caacd54cfa2217f258625fd539cc387cefb2c;hpb=36f4aab18ccf897b405f137d6cd4f9673bd947fc;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index fe3caacd54..6567880efb 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -1,5 +1,5 @@ /* aarch64-dis.c -- AArch64 disassembler. - Copyright (C) 2009-2015 Free Software Foundation, Inc. + Copyright (C) 2009-2020 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of the GNU opcodes library. @@ -20,17 +20,12 @@ #include "sysdep.h" #include "bfd_stdint.h" -#include "dis-asm.h" +#include "disassemble.h" #include "libiberty.h" #include "opintl.h" #include "aarch64-dis.h" #include "elf-bfd.h" -#define ERR_OK 0 -#define ERR_UND -1 -#define ERR_UNP -3 -#define ERR_NYI -5 - #define INSNLEN 4 /* Cached mapping symbol state. */ @@ -42,11 +37,16 @@ enum map_type static enum map_type last_type; static int last_mapping_sym = -1; +static bfd_vma last_stop_offset = 0; static bfd_vma last_mapping_addr = 0; /* Other options */ static int no_aliases = 0; /* If set disassemble as most general inst. */ - + static int no_notes = 1; /* If set do not print disassemble notes in the + output as comments. */ + +/* Currently active instruction sequence. */ +static aarch64_instr_sequence insn_sequence; static void set_default_aarch64_dis_options (struct disassemble_info *info ATTRIBUTE_UNUSED) @@ -69,6 +69,18 @@ parse_aarch64_dis_option (const char *option, unsigned int len ATTRIBUTE_UNUSED) return; } + if (CONST_STRNEQ (option, "no-notes")) + { + no_notes = 1; + return; + } + + if (CONST_STRNEQ (option, "notes")) + { + no_notes = 0; + return; + } + #ifdef DEBUG_AARCH64 if (CONST_STRNEQ (option, "debug_dump")) { @@ -78,7 +90,7 @@ parse_aarch64_dis_option (const char *option, unsigned int len ATTRIBUTE_UNUSED) #endif /* DEBUG_AARCH64 */ /* Invalid option. */ - fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); + opcodes_error_handler (_("unrecognised disassembler option: %s"), option); } static void @@ -123,7 +135,7 @@ parse_aarch64_dis_options (const char *options) is encoded in H:L:M in some cases, the fields H:L:M should be passed in the order of H, L, M. */ -static inline aarch64_insn +aarch64_insn extract_fields (aarch64_insn code, aarch64_insn mask, ...) { uint32_t num; @@ -145,19 +157,36 @@ extract_fields (aarch64_insn code, aarch64_insn mask, ...) return value; } +/* Extract the value of all fields in SELF->fields from instruction CODE. + The least significant bit comes from the final field. */ + +static aarch64_insn +extract_all_fields (const aarch64_operand *self, aarch64_insn code) +{ + aarch64_insn value; + unsigned int i; + enum aarch64_field_kind kind; + + value = 0; + for (i = 0; i < ARRAY_SIZE (self->fields) && self->fields[i] != FLD_NIL; ++i) + { + kind = self->fields[i]; + value <<= fields[kind].width; + value |= extract_field (kind, code, 0); + } + return value; +} + /* Sign-extend bit I of VALUE. */ -static inline int32_t +static inline uint64_t sign_extend (aarch64_insn value, unsigned i) { - uint32_t ret = value; + uint64_t ret, sign; assert (i < 32); - if ((value >> i) & 0x1) - { - uint32_t val = (uint32_t)(-1) << i; - ret = ret | val; - } - return (int32_t) ret; + ret = value; + sign = (uint64_t) 1 << i; + return ((ret & (sign + sign - 1)) ^ sign) - sign; } /* N.B. the following inline helpfer functions create a dependency on the @@ -173,12 +202,19 @@ get_greg_qualifier_from_value (aarch64_insn value) return qualifier; } -/* Given VALUE, return qualifier for a vector register. */ +/* Given VALUE, return qualifier for a vector register. This does not support + decoding instructions that accept the 2H vector type. */ + static inline enum aarch64_opnd_qualifier get_vreg_qualifier_from_value (aarch64_insn value) { enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_V_8B + value; + /* Instructions using vector type 2H should not call this function. Skip over + the 2H qualifier. */ + if (qualifier >= AARCH64_OPND_QLF_V_2H) + qualifier += 1; + assert (value <= 0x8 && aarch64_get_qualifier_standard_value (qualifier) == value); return qualifier; @@ -215,31 +251,44 @@ get_expected_qualifier (const aarch64_inst *inst, int i) /* Operand extractors. */ -int +bfd_boolean +aarch64_ext_none (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info ATTRIBUTE_UNUSED, + const aarch64_insn code ATTRIBUTE_UNUSED, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +bfd_boolean aarch64_ext_regno (const aarch64_operand *self, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { info->reg.regno = extract_field (self->fields[0], code, 0); - return 1; + return TRUE; } -int +bfd_boolean aarch64_ext_regno_pair (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code ATTRIBUTE_UNUSED, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { assert (info->idx == 1 || info->idx ==3); info->reg.regno = inst->operands[info->idx - 1].reg.regno + 1; - return 1; + return TRUE; } /* e.g. IC {, }. */ -int +bfd_boolean aarch64_ext_regrt_sysins (const aarch64_operand *self, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { info->reg.regno = extract_field (self->fields[0], code, 0); assert (info->idx == 1 @@ -248,16 +297,17 @@ aarch64_ext_regrt_sysins (const aarch64_operand *self, aarch64_opnd_info *info, /* This will make the constraint checking happy and more importantly will help the disassembler determine whether this operand is optional or not. */ - info->present = inst->operands[0].sysins_op->has_xt; + info->present = aarch64_sys_ins_reg_has_xt (inst->operands[0].sysins_op); - return 1; + return TRUE; } /* e.g. SQDMLAL , , .[]. */ -int +bfd_boolean aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { /* regno */ info->reglane.regno = extract_field (self->fields[0], code, @@ -293,11 +343,32 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info, while (++pos <= 3 && (value & 0x1) == 0) value >>= 1; if (pos > 3) - return 0; + return FALSE; info->qualifier = get_sreg_qualifier_from_value (pos); info->reglane.index = (unsigned) (value >> 1); } } + else if (inst->opcode->iclass == dotproduct) + { + /* Need information in other operand(s) to help decoding. */ + info->qualifier = get_expected_qualifier (inst, info->idx); + switch (info->qualifier) + { + case AARCH64_OPND_QLF_S_4B: + case AARCH64_OPND_QLF_S_2H: + /* L:H */ + info->reglane.index = extract_fields (code, 0, 2, FLD_H, FLD_L); + info->reglane.regno &= 0x1f; + break; + default: + return FALSE; + } + } + else if (inst->opcode->iclass == cryptosm3) + { + /* index for e.g. SM3TT2A .4S, .4S, S[]. */ + info->reglane.index = extract_field (FLD_SM3_imm2, code, 0); + } else { /* Index only for e.g. SQDMLAL , , .[] @@ -308,10 +379,18 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info, switch (info->qualifier) { case AARCH64_OPND_QLF_S_H: - /* h:l:m */ - info->reglane.index = extract_fields (code, 0, 3, FLD_H, FLD_L, - FLD_M); - info->reglane.regno &= 0xf; + if (info->type == AARCH64_OPND_Em16) + { + /* h:l:m */ + info->reglane.index = extract_fields (code, 0, 3, FLD_H, FLD_L, + FLD_M); + info->reglane.regno &= 0xf; + } + else + { + /* h:l */ + info->reglane.index = extract_fields (code, 0, 2, FLD_H, FLD_L); + } break; case AARCH64_OPND_QLF_S_S: /* h:l */ @@ -322,30 +401,41 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info, info->reglane.index = extract_field (FLD_H, code, 0); break; default: - return 0; + return FALSE; + } + + if (inst->opcode->op == OP_FCMLA_ELEM + && info->qualifier != AARCH64_OPND_QLF_S_H) + { + /* Complex operand takes two elements. */ + if (info->reglane.index & 1) + return FALSE; + info->reglane.index /= 2; } } - return 1; + return TRUE; } -int +bfd_boolean aarch64_ext_reglist (const aarch64_operand *self, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { /* R */ info->reglist.first_regno = extract_field (self->fields[0], code, 0); /* len */ info->reglist.num_regs = extract_field (FLD_len, code, 0) + 1; - return 1; + return TRUE; } /* Decode Rt and opcode fields of Vt in AdvSIMD load/store instructions. */ -int +bfd_boolean aarch64_ext_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst) + const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { aarch64_insn value; /* Number of elements in each structure to be loaded/stored. */ @@ -374,19 +464,23 @@ aarch64_ext_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED, info->reglist.first_regno = extract_field (FLD_Rt, code, 0); /* opcode */ value = extract_field (FLD_opcode, code, 0); + /* PR 21595: Check for a bogus value. */ + if (value >= ARRAY_SIZE (data)) + return FALSE; if (expected_num != data[value].num_elements || data[value].is_reserved) - return 0; + return FALSE; info->reglist.num_regs = data[value].num_regs; - return 1; + return TRUE; } /* Decode Rt and S fields of Vt in AdvSIMD load single structure to all lanes instructions. */ -int +bfd_boolean aarch64_ext_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst) + const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { aarch64_insn value; @@ -404,15 +498,16 @@ aarch64_ext_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED, if (info->reglist.num_regs == 1 && value == (aarch64_insn) 1) info->reglist.num_regs = 2; - return 1; + return TRUE; } /* Decode Q, opcode<2:1>, S, size and Rt fields of Vt in AdvSIMD load/store single element instructions. */ -int +bfd_boolean aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { aarch64_field field = {0, 0}; aarch64_insn QSsize; /* fields Q:S:size. */ @@ -435,7 +530,7 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED, case 0x1: if (QSsize & 0x1) /* UND. */ - return 0; + return FALSE; info->qualifier = AARCH64_OPND_QLF_S_H; /* Index encoded in "Q:S:size<1>". */ info->reglist.index = QSsize >> 1; @@ -443,7 +538,7 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED, case 0x2: if ((QSsize >> 1) & 0x1) /* UND. */ - return 0; + return FALSE; if ((QSsize & 0x1) == 0) { info->qualifier = AARCH64_OPND_QLF_S_S; @@ -454,14 +549,14 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED, { if (extract_field (FLD_S, code, 0)) /* UND */ - return 0; + return FALSE; info->qualifier = AARCH64_OPND_QLF_S_D; /* Index encoded in "Q". */ info->reglist.index = QSsize >> 3; } break; default: - return 0; + return FALSE; } info->reglist.has_index = 1; @@ -471,17 +566,18 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED, info->reglist.num_regs = get_opcode_dependent_value (inst->opcode); assert (info->reglist.num_regs >= 1 && info->reglist.num_regs <= 4); - return 1; + return TRUE; } /* Decode fields immh:immb and/or Q for e.g. SSHR ., ., # or SSHR , , #. */ -int +bfd_boolean aarch64_ext_advsimd_imm_shift (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst) + const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { int pos; aarch64_insn Q, imm, immh; @@ -489,7 +585,7 @@ aarch64_ext_advsimd_imm_shift (const aarch64_operand *self ATTRIBUTE_UNUSED, immh = extract_field (FLD_immh, code, 0); if (immh == 0) - return 0; + return FALSE; imm = extract_fields (code, 0, 2, FLD_immh, FLD_immb); pos = 4; /* Get highest set bit in immh. */ @@ -537,14 +633,15 @@ aarch64_ext_advsimd_imm_shift (const aarch64_operand *self ATTRIBUTE_UNUSED, 1xxx (UInt(immh:immb)-64) */ info->imm.value = imm - (8 << pos); - return 1; + return TRUE; } /* Decode shift immediate for e.g. sshr (imm). */ -int +bfd_boolean aarch64_ext_shll_imm (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { int64_t imm; aarch64_insn val; @@ -554,64 +651,60 @@ aarch64_ext_shll_imm (const aarch64_operand *self ATTRIBUTE_UNUSED, case 0: imm = 8; break; case 1: imm = 16; break; case 2: imm = 32; break; - default: return 0; + default: return FALSE; } info->imm.value = imm; - return 1; + return TRUE; } /* Decode imm for e.g. BFM , , #, #. value in the field(s) will be extracted as unsigned immediate value. */ -int +bfd_boolean aarch64_ext_imm (const aarch64_operand *self, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { - int64_t imm; - /* Maximum of two fields to extract. */ - assert (self->fields[2] == FLD_NIL); - - if (self->fields[1] == FLD_NIL) - imm = extract_field (self->fields[0], code, 0); - else - /* e.g. TBZ b5:b40. */ - imm = extract_fields (code, 0, 2, self->fields[0], self->fields[1]); + uint64_t imm; - if (info->type == AARCH64_OPND_FPIMM) - info->imm.is_fp = 1; + imm = extract_all_fields (self, code); if (operand_need_sign_extension (self)) imm = sign_extend (imm, get_operand_fields_width (self) - 1); if (operand_need_shift_by_two (self)) imm <<= 2; + else if (operand_need_shift_by_four (self)) + imm <<= 4; if (info->type == AARCH64_OPND_ADDR_ADRP) imm <<= 12; info->imm.value = imm; - return 1; + return TRUE; } /* Decode imm and its shifter for e.g. MOVZ , #{, LSL #}. */ -int +bfd_boolean aarch64_ext_imm_half (const aarch64_operand *self, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors) { - aarch64_ext_imm (self, info, code, inst); + aarch64_ext_imm (self, info, code, inst, errors); info->shifter.kind = AARCH64_MOD_LSL; info->shifter.amount = extract_field (FLD_hw, code, 0) << 4; - return 1; + return TRUE; } /* Decode cmode and "a:b:c:d:e:f:g:h" for e.g. MOVI ., # {, LSL #}. */ -int +bfd_boolean aarch64_ext_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { uint64_t imm; enum aarch64_opnd_qualifier opnd0_qualifier = inst->operands[0].qualifier; @@ -655,7 +748,7 @@ aarch64_ext_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED, case 4: gen_sub_field (FLD_cmode, 1, 2, &field); break; /* per word */ case 2: gen_sub_field (FLD_cmode, 1, 1, &field); break; /* per half */ case 1: gen_sub_field (FLD_cmode, 1, 0, &field); break; /* per byte */ - default: assert (0); return 0; + default: assert (0); return FALSE; } /* 00: 0; 01: 8; 10:16; 11:24. */ info->shifter.amount = extract_field_2 (&field, code, 0) << 3; @@ -668,28 +761,68 @@ aarch64_ext_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED, break; default: assert (0); - return 0; + return FALSE; } - return 1; + return TRUE; +} + +/* Decode an 8-bit floating-point immediate. */ +bfd_boolean +aarch64_ext_fpimm (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + info->imm.value = extract_all_fields (self, code); + info->imm.is_fp = 1; + return TRUE; +} + +/* Decode a 1-bit rotate immediate (#90 or #270). */ +bfd_boolean +aarch64_ext_imm_rotate1 (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + uint64_t rot = extract_field (self->fields[0], code, 0); + assert (rot < 2U); + info->imm.value = rot * 180 + 90; + return TRUE; +} + +/* Decode a 2-bit rotate immediate (#0, #90, #180 or #270). */ +bfd_boolean +aarch64_ext_imm_rotate2 (const aarch64_operand *self, aarch64_opnd_info *info, + const aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + uint64_t rot = extract_field (self->fields[0], code, 0); + assert (rot < 4U); + info->imm.value = rot * 90; + return TRUE; } /* Decode scale for e.g. SCVTF
, , #. */ -int +bfd_boolean aarch64_ext_fbits (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { info->imm.value = 64- extract_field (FLD_scale, code, 0); - return 1; + return TRUE; } /* Decode arithmetic immediate for e.g. SUBS , , # {, }. */ -int +bfd_boolean aarch64_ext_aimm (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { aarch64_insn value; @@ -697,40 +830,29 @@ aarch64_ext_aimm (const aarch64_operand *self ATTRIBUTE_UNUSED, /* shift */ value = extract_field (FLD_shift, code, 0); if (value >= 2) - return 0; + return FALSE; info->shifter.amount = value ? 12 : 0; /* imm12 (unsigned) */ info->imm.value = extract_field (FLD_imm12, code, 0); - return 1; + return TRUE; } -/* Decode logical immediate for e.g. ORR , , #. */ - -int -aarch64_ext_limm (const aarch64_operand *self ATTRIBUTE_UNUSED, - aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) +/* Return true if VALUE is a valid logical immediate encoding, storing the + decoded value in *RESULT if so. ESIZE is the number of bytes in the + decoded immediate. */ +static bfd_boolean +decode_limm (uint32_t esize, aarch64_insn value, int64_t *result) { uint64_t imm, mask; - uint32_t sf; uint32_t N, R, S; unsigned simd_size; - aarch64_insn value; - - value = extract_fields (code, 0, 3, FLD_N, FLD_immr, FLD_imms); - assert (inst->operands[0].qualifier == AARCH64_OPND_QLF_W - || inst->operands[0].qualifier == AARCH64_OPND_QLF_X); - sf = aarch64_get_qualifier_esize (inst->operands[0].qualifier) != 4; /* value is N:immr:imms. */ S = value & 0x3f; R = (value >> 6) & 0x3f; N = (value >> 12) & 0x1; - if (sf == 0 && N == 1) - return 0; - /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R (in other words, right rotated by R), then replicated. */ if (N != 0) @@ -747,15 +869,19 @@ aarch64_ext_limm (const aarch64_operand *self ATTRIBUTE_UNUSED, case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break; case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break; case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break; - default: return 0; + default: return FALSE; } mask = (1ull << simd_size) - 1; /* Top bits are IGNORED. */ R &= simd_size - 1; } + + if (simd_size > esize * 8) + return FALSE; + /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */ if (S == simd_size - 1) - return 0; + return FALSE; /* S+1 consecutive bits to 1. */ /* NOTE: S can't be 63 due to detection above. */ imm = (1ull << (S + 1)) - 1; @@ -766,25 +892,60 @@ aarch64_ext_limm (const aarch64_operand *self ATTRIBUTE_UNUSED, switch (simd_size) { case 2: imm = (imm << 2) | imm; + /* Fall through. */ case 4: imm = (imm << 4) | imm; + /* Fall through. */ case 8: imm = (imm << 8) | imm; + /* Fall through. */ case 16: imm = (imm << 16) | imm; + /* Fall through. */ case 32: imm = (imm << 32) | imm; + /* Fall through. */ case 64: break; default: assert (0); return 0; } - info->imm.value = sf ? imm : imm & 0xffffffff; + *result = imm & ~((uint64_t) -1 << (esize * 4) << (esize * 4)); - return 1; + return TRUE; +} + +/* Decode a logical immediate for e.g. ORR , , #. */ +bfd_boolean +aarch64_ext_limm (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + uint32_t esize; + aarch64_insn value; + + value = extract_fields (code, 0, 3, self->fields[0], self->fields[1], + self->fields[2]); + esize = aarch64_get_qualifier_esize (inst->operands[0].qualifier); + return decode_limm (esize, value, &info->imm.value); +} + +/* Decode a logical immediate for the BIC alias of AND (etc.). */ +bfd_boolean +aarch64_ext_inv_limm (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst, + aarch64_operand_error *errors) +{ + if (!aarch64_ext_limm (self, info, code, inst, errors)) + return FALSE; + info->imm.value = ~info->imm.value; + return TRUE; } /* Decode Ft for e.g. STR , [, {, {}}] or LDP , , [], #. */ -int +bfd_boolean aarch64_ext_ft (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, - const aarch64_insn code, const aarch64_inst *inst) + const aarch64_insn code, const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { aarch64_insn value; @@ -804,7 +965,7 @@ aarch64_ext_ft (const aarch64_operand *self ATTRIBUTE_UNUSED, case 0: qualifier = AARCH64_OPND_QLF_S_S; break; case 1: qualifier = AARCH64_OPND_QLF_S_D; break; case 2: qualifier = AARCH64_OPND_QLF_S_Q; break; - default: return 0; + default: return FALSE; } info->qualifier = qualifier; } @@ -813,31 +974,56 @@ aarch64_ext_ft (const aarch64_operand *self ATTRIBUTE_UNUSED, /* opc1:size */ value = extract_fields (code, 0, 2, FLD_opc1, FLD_ldst_size); if (value > 0x4) - return 0; + return FALSE; info->qualifier = get_sreg_qualifier_from_value (value); } - return 1; + return TRUE; } /* Decode the address operand for e.g. STXRB , , [{,#0}]. */ -int +bfd_boolean aarch64_ext_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { /* Rn */ info->addr.base_regno = extract_field (FLD_Rn, code, 0); - return 1; + return TRUE; +} + +/* Decode the address operand for e.g. + stlur , [{, }]. */ +bfd_boolean +aarch64_ext_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + info->qualifier = get_expected_qualifier (inst, info->idx); + + /* Rn */ + info->addr.base_regno = extract_field (self->fields[0], code, 0); + + /* simm9 */ + aarch64_insn imm = extract_fields (code, 0, 1, self->fields[1]); + info->addr.offset.imm = sign_extend (imm, 8); + if (extract_field (self->fields[2], code, 0) == 1) { + info->addr.writeback = 1; + info->addr.preind = 1; + } + return TRUE; } /* Decode the address operand for e.g. STR , [, {, {}}]. */ -int +bfd_boolean aarch64_ext_addr_regoff (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, - aarch64_insn code, const aarch64_inst *inst) + aarch64_insn code, const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { aarch64_insn S, value; @@ -873,13 +1059,14 @@ aarch64_ext_addr_regoff (const aarch64_operand *self ATTRIBUTE_UNUSED, info->shifter.amount_present = 1; } - return 1; + return TRUE; } /* Decode the address operand for e.g. LDRSW , [], #. */ -int +bfd_boolean aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info, - aarch64_insn code, const aarch64_inst *inst) + aarch64_insn code, const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { aarch64_insn imm; info->qualifier = get_expected_qualifier (inst, info->idx); @@ -889,7 +1076,8 @@ aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info, /* simm (imm9 or imm7) */ imm = extract_field (self->fields[0], code, 0); info->addr.offset.imm = sign_extend (imm, fields[self->fields[0]].width - 1); - if (self->fields[0] == FLD_imm7) + if (self->fields[0] == FLD_imm7 + || info->qualifier == AARCH64_OPND_QLF_imm_tag) /* scaled immediate in ld/st pair instructions. */ info->addr.offset.imm *= aarch64_get_qualifier_esize (info->qualifier); /* qualifier */ @@ -908,14 +1096,15 @@ aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info, info->addr.postind = 1; } - return 1; + return TRUE; } /* Decode the address operand for e.g. LDRSW , [{, #}]. */ -int +bfd_boolean aarch64_ext_addr_uimm12 (const aarch64_operand *self, aarch64_opnd_info *info, aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { int shift; info->qualifier = get_expected_qualifier (inst, info->idx); @@ -924,15 +1113,38 @@ aarch64_ext_addr_uimm12 (const aarch64_operand *self, aarch64_opnd_info *info, info->addr.base_regno = extract_field (self->fields[0], code, 0); /* uimm12 */ info->addr.offset.imm = extract_field (self->fields[1], code, 0) << shift; - return 1; + return TRUE; +} + +/* Decode the address operand for e.g. LDRAA , [{, #}]. */ +bfd_boolean +aarch64_ext_addr_simm10 (const aarch64_operand *self, aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + aarch64_insn imm; + + info->qualifier = get_expected_qualifier (inst, info->idx); + /* Rn */ + info->addr.base_regno = extract_field (self->fields[0], code, 0); + /* simm10 */ + imm = extract_fields (code, 0, 2, self->fields[1], self->fields[2]); + info->addr.offset.imm = sign_extend (imm, 9) << 3; + if (extract_field (self->fields[3], code, 0) == 1) { + info->addr.writeback = 1; + info->addr.preind = 1; + } + return TRUE; } /* Decode the address operand for e.g. LD1 {., ., .}, [], >. */ -int +bfd_boolean aarch64_ext_simd_addr_post (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, - aarch64_insn code, const aarch64_inst *inst) + aarch64_insn code, const aarch64_inst *inst, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { /* The opcode dependent area stores the number of elements in each structure to be loaded/stored. */ @@ -958,57 +1170,76 @@ aarch64_ext_simd_addr_post (const aarch64_operand *self ATTRIBUTE_UNUSED, info->addr.offset.is_reg = 1; info->addr.writeback = 1; - return 1; + return TRUE; } /* Decode the condition operand for e.g. CSEL , , , . */ -int +bfd_boolean aarch64_ext_cond (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, - aarch64_insn code, const aarch64_inst *inst ATTRIBUTE_UNUSED) + aarch64_insn code, const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { aarch64_insn value; /* cond */ value = extract_field (FLD_cond, code, 0); info->cond = get_cond_from_value (value); - return 1; + return TRUE; } /* Decode the system register operand for e.g. MRS , . */ -int +bfd_boolean aarch64_ext_sysreg (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { /* op0:op1:CRn:CRm:op2 */ - info->sysreg = extract_fields (code, 0, 5, FLD_op0, FLD_op1, FLD_CRn, - FLD_CRm, FLD_op2); - return 1; + info->sysreg.value = extract_fields (code, 0, 5, FLD_op0, FLD_op1, FLD_CRn, + FLD_CRm, FLD_op2); + info->sysreg.flags = 0; + + /* If a system instruction, check which restrictions should be on the register + value during decoding, these will be enforced then. */ + if (inst->opcode->iclass == ic_system) + { + /* Check to see if it's read-only, else check if it's write only. + if it's both or unspecified don't care. */ + if ((inst->opcode->flags & (F_SYS_READ | F_SYS_WRITE)) == F_SYS_READ) + info->sysreg.flags = F_REG_READ; + else if ((inst->opcode->flags & (F_SYS_READ | F_SYS_WRITE)) + == F_SYS_WRITE) + info->sysreg.flags = F_REG_WRITE; + } + + return TRUE; } /* Decode the PSTATE field operand for e.g. MSR , #. */ -int +bfd_boolean aarch64_ext_pstatefield (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { int i; /* op1:op2 */ info->pstatefield = extract_fields (code, 0, 2, FLD_op1, FLD_op2); for (i = 0; aarch64_pstatefields[i].name != NULL; ++i) if (aarch64_pstatefields[i].value == (aarch64_insn)info->pstatefield) - return 1; + return TRUE; /* Reserved value in . */ - return 0; + return FALSE; } /* Decode the system instruction op operand for e.g. AT , . */ -int +bfd_boolean aarch64_ext_sysins_op (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info, aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) { int i; aarch64_insn value; @@ -1024,110 +1255,602 @@ aarch64_ext_sysins_op (const aarch64_operand *self ATTRIBUTE_UNUSED, case AARCH64_OPND_SYSREG_DC: sysins_ops = aarch64_sys_regs_dc; break; case AARCH64_OPND_SYSREG_IC: sysins_ops = aarch64_sys_regs_ic; break; case AARCH64_OPND_SYSREG_TLBI: sysins_ops = aarch64_sys_regs_tlbi; break; - default: assert (0); return 0; + case AARCH64_OPND_SYSREG_SR: + sysins_ops = aarch64_sys_regs_sr; + /* Let's remove op2 for rctx. Refer to comments in the definition of + aarch64_sys_regs_sr[]. */ + value = value & ~(0x7); + break; + default: assert (0); return FALSE; } - for (i = 0; sysins_ops[i].template != NULL; ++i) + for (i = 0; sysins_ops[i].name != NULL; ++i) if (sysins_ops[i].value == value) { info->sysins_op = sysins_ops + i; DEBUG_TRACE ("%s found value: %x, has_xt: %d, i: %d.", - info->sysins_op->template, + info->sysins_op->name, (unsigned)info->sysins_op->value, - info->sysins_op->has_xt, i); - return 1; + aarch64_sys_ins_reg_has_xt (info->sysins_op), i); + return TRUE; } - return 0; + return FALSE; } /* Decode the memory barrier option operand for e.g. DMB