#define MX { OP_MMX, 0 }
#define XM { OP_XMM, 0 }
#define XMScalar { OP_XMM, scalar_mode }
+#define XMGatherD { OP_XMM, vex_vsib_d_w_dq_mode }
#define XMGatherQ { OP_XMM, vex_vsib_q_w_dq_mode }
#define XMM { OP_XMM, xmm_mode }
#define TMM { OP_XMM, tmm_mode }
#define VexW { OP_VexW, vex_mode }
#define VexScalar { OP_VEX, vex_scalar_mode }
#define VexScalarR { OP_VexR, vex_scalar_mode }
+#define VexGatherD { OP_VEX, vex_vsib_d_w_dq_mode }
#define VexGatherQ { OP_VEX, vex_vsib_q_w_dq_mode }
#define VexGdq { OP_VEX, dq_mode }
#define VexTmm { OP_VEX, tmm_mode }
#define MaskVex { OP_VEX, mask_mode }
#define MVexVSIBDWpX { OP_M, vex_vsib_d_w_dq_mode }
-#define MVexVSIBDQWpX { OP_M, vex_vsib_d_w_d_mode }
#define MVexVSIBQWpX { OP_M, vex_vsib_q_w_dq_mode }
-#define MVexVSIBQDWpX { OP_M, vex_vsib_q_w_d_mode }
#define MVexSIBMEM { OP_M, vex_sibmem_mode }
/* Operand size depends on the VEX.W bit, with VSIB dword indices. */
vex_vsib_d_w_dq_mode,
- /* Similar to vex_vsib_d_w_dq_mode, with smaller memory. */
- vex_vsib_d_w_d_mode,
/* Operand size depends on the VEX.W bit, with VSIB qword indices. */
vex_vsib_q_w_dq_mode,
- /* Similar to vex_vsib_q_w_dq_mode, with smaller memory. */
- vex_vsib_q_w_d_mode,
/* mandatory non-vector SIB. */
vex_sibmem_mode,
REG_EVEX_0F72,
REG_EVEX_0F73,
REG_EVEX_0F38C6_M_0_L_2,
- REG_EVEX_0F38C7_M_0_L_2_W_0,
- REG_EVEX_0F38C7_M_0_L_2_W_1
+ REG_EVEX_0F38C7_M_0_L_2
};
enum
EVEX_W_0F387A,
EVEX_W_0F387B,
EVEX_W_0F3883,
- EVEX_W_0F3891,
- EVEX_W_0F3893,
- EVEX_W_0F38A1,
- EVEX_W_0F38A3,
- EVEX_W_0F38C7_M_0_L_2,
EVEX_W_0F3A05,
EVEX_W_0F3A08,
{ MOD_TABLE (MOD_VEX_0F388E) },
{ Bad_Opcode },
/* 90 */
- { "vpgatherd%DQ", { XM, MVexVSIBDWpX, Vex }, PREFIX_DATA },
+ { "vpgatherd%DQ", { XM, MVexVSIBDWpX, VexGatherD }, PREFIX_DATA },
{ "vpgatherq%DQ", { XMGatherQ, MVexVSIBQWpX, VexGatherQ }, PREFIX_DATA },
- { "vgatherdp%XW", { XM, MVexVSIBDWpX, Vex }, PREFIX_DATA },
+ { "vgatherdp%XW", { XM, MVexVSIBDWpX, VexGatherD }, PREFIX_DATA },
{ "vgatherqp%XW", { XMGatherQ, MVexVSIBQWpX, VexGatherQ }, PREFIX_DATA },
{ Bad_Opcode },
{ Bad_Opcode },
#define NOTRACK_PREFIX (0x3e | 0x100)
/* Remember if the current op is a jump instruction. */
-static bfd_boolean op_is_jump = FALSE;
+static bool op_is_jump = false;
static int
ckprefix (void)
for (p = info->disassembler_options; p != NULL; )
{
- if (CONST_STRNEQ (p, "amd64"))
+ if (startswith (p, "amd64"))
isa64 = amd64;
- else if (CONST_STRNEQ (p, "intel64"))
+ else if (startswith (p, "intel64"))
isa64 = intel64;
- else if (CONST_STRNEQ (p, "x86-64"))
+ else if (startswith (p, "x86-64"))
{
address_mode = mode_64bit;
priv.orig_sizeflag |= AFLAG | DFLAG;
}
- else if (CONST_STRNEQ (p, "i386"))
+ else if (startswith (p, "i386"))
{
address_mode = mode_32bit;
priv.orig_sizeflag |= AFLAG | DFLAG;
}
- else if (CONST_STRNEQ (p, "i8086"))
+ else if (startswith (p, "i8086"))
{
address_mode = mode_16bit;
priv.orig_sizeflag &= ~(AFLAG | DFLAG);
}
- else if (CONST_STRNEQ (p, "intel"))
+ else if (startswith (p, "intel"))
{
intel_syntax = 1;
- if (CONST_STRNEQ (p + 5, "-mnemonic"))
+ if (startswith (p + 5, "-mnemonic"))
intel_mnemonic = 1;
}
- else if (CONST_STRNEQ (p, "att"))
+ else if (startswith (p, "att"))
{
intel_syntax = 0;
- if (CONST_STRNEQ (p + 3, "-mnemonic"))
+ if (startswith (p + 3, "-mnemonic"))
intel_mnemonic = 0;
}
- else if (CONST_STRNEQ (p, "addr"))
+ else if (startswith (p, "addr"))
{
if (address_mode == mode_64bit)
{
priv.orig_sizeflag |= AFLAG;
}
}
- else if (CONST_STRNEQ (p, "data"))
+ else if (startswith (p, "data"))
{
if (p[4] == '1' && p[5] == '6')
priv.orig_sizeflag &= ~DFLAG;
else if (p[4] == '3' && p[5] == '2')
priv.orig_sizeflag |= DFLAG;
}
- else if (CONST_STRNEQ (p, "suffix"))
+ else if (startswith (p, "suffix"))
priv.orig_sizeflag |= SUFFIX_ALWAYS;
p = strchr (p, ',');
}
if (vex.zeroing)
oappend ("{z}");
+
+ /* S/G insns require a mask and don't allow
+ zeroing-masking. */
+ if ((dp->op[0].bytemode == vex_vsib_d_w_dq_mode
+ || dp->op[0].bytemode == vex_vsib_q_w_dq_mode)
+ && (vex.mask_register_specifier == 0 || vex.zeroing))
+ oappend ("/(bad)");
}
}
}
}
/* Reset jump operation indicator. */
- op_is_jump = FALSE;
+ op_is_jump = false;
{
int jump_detection = 0;
/* Determine if this is a jump or branch. */
if ((jump_detection & 0x3) == 0x3)
{
- op_is_jump = TRUE;
+ op_is_jump = true;
if (jump_detection & 0x4)
the_info->insn_type = dis_condbranch;
else
return end_codep - priv.the_buffer;
}
+ /* If EVEX.z is set, there must be an actual mask register in use. */
+ if (vex.zeroing && vex.mask_register_specifier == 0)
+ {
+ (*info->fprintf_func) (info->stream, "(bad)");
+ return end_codep - priv.the_buffer;
+ }
+
switch (dp->prefix_requirement)
{
case PREFIX_DATA:
origins in all_prefixes. */
used_prefixes &= ~PREFIX_OPCODE;
if (last_data_prefix >= 0)
- all_prefixes[last_repz_prefix] = 0x66;
+ all_prefixes[last_data_prefix] = 0x66;
if (last_repz_prefix >= 0)
all_prefixes[last_repz_prefix] = 0xf3;
if (last_repnz_prefix >= 0)
}
else if (l == 1 && last[0] == 'X')
{
- if (!need_vex || !vex.evex)
+ if (!vex.evex)
abort ();
if (intel_syntax
|| ((modrm.mod == 3 || vex.b) && !(sizeflag & SUFFIX_ALWAYS)))
static void
intel_operand_size (int bytemode, int sizeflag)
{
- if (vex.evex
- && vex.b
+ if (vex.b
&& (bytemode == x_mode
|| bytemode == evex_half_bcst_xmmq_mode))
{
if (!need_vex)
abort ();
- if (!vex.evex)
- {
- if (vex.w)
- oappend ("QWORD PTR ");
- else
- oappend ("DWORD PTR ");
- }
+ if (vex.w)
+ oappend ("QWORD PTR ");
else
- {
- switch (vex.length)
- {
- case 128:
- oappend ("XMMWORD PTR ");
- break;
- case 256:
- oappend ("YMMWORD PTR ");
- break;
- case 512:
- oappend ("ZMMWORD PTR ");
- break;
- default:
- abort ();
- }
- }
- break;
- case vex_vsib_q_w_d_mode:
- case vex_vsib_d_w_d_mode:
- if (!need_vex || !vex.evex)
- abort ();
-
- switch (vex.length)
- {
- case 128:
- oappend ("QWORD PTR ");
- break;
- case 256:
- oappend ("XMMWORD PTR ");
- break;
- case 512:
- oappend ("YMMWORD PTR ");
- break;
- default:
- abort ();
- }
-
+ oappend ("DWORD PTR ");
break;
case mask_bd_mode:
if (!need_vex || vex.length != 128)
/* In EVEX, if operand doesn't allow broadcast, vex.b should be 0. */
if (vex.b
&& bytemode != x_mode
- && bytemode != xmmq_mode
&& bytemode != evex_half_bcst_xmmq_mode)
{
BadOp ();
/* fall through */
case vex_scalar_w_dq_mode:
case vex_vsib_d_w_dq_mode:
- case vex_vsib_d_w_d_mode:
case vex_vsib_q_w_dq_mode:
- case vex_vsib_q_w_d_mode:
case evex_x_gscat_mode:
shift = vex.w ? 3 : 2;
break;
case x_mode:
case evex_half_bcst_xmmq_mode:
- case xmmq_mode:
if (vex.b)
{
shift = vex.w ? 3 : 2;
/* Fall through. */
case xmmqd_mode:
case xmmdw_mode:
+ case xmmq_mode:
case ymmq_mode:
case evex_x_nobcst_mode:
case x_swap_mode:
|| bytemode == v_bndmk_mode
|| bytemode == bnd_mode
|| bytemode == bnd_swap_mode);
+ bool check_gather = false;
const char **indexes64 = names64;
const char **indexes32 = names32;
switch (bytemode)
{
case vex_vsib_d_w_dq_mode:
- case vex_vsib_d_w_d_mode:
case vex_vsib_q_w_dq_mode:
- case vex_vsib_q_w_d_mode:
if (!need_vex)
abort ();
if (vex.evex)
{
if (!vex.v)
vindex += 16;
+ check_gather = obufp == op_out[1];
}
haveindex = 1;
break;
case 256:
if (!vex.w
- || bytemode == vex_vsib_q_w_dq_mode
- || bytemode == vex_vsib_q_w_d_mode)
+ || bytemode == vex_vsib_q_w_dq_mode)
indexes64 = indexes32 = names_ymm;
else
indexes64 = indexes32 = names_xmm;
break;
case 512:
if (!vex.w
- || bytemode == vex_vsib_q_w_dq_mode
- || bytemode == vex_vsib_q_w_d_mode)
+ || bytemode == vex_vsib_q_w_dq_mode)
indexes64 = indexes32 = names_zmm;
else
indexes64 = indexes32 = names_ymm;
}
else
{
- /* mandatory non-vector SIB must have sib */
- if (bytemode == vex_sibmem_mode)
+ /* Check for mandatory SIB. */
+ if (bytemode == vex_vsib_d_w_dq_mode
+ || bytemode == vex_vsib_q_w_dq_mode
+ || bytemode == vex_sibmem_mode)
{
oappend ("(bad)");
return;
*obufp++ = close_char;
*obufp = '\0';
+
+ if (check_gather)
+ {
+ /* Both XMM/YMM/ZMM registers must be distinct. */
+ int modrm_reg = modrm.reg;
+
+ if (rex & REX_R)
+ modrm_reg += 8;
+ if (!vex.r)
+ modrm_reg += 16;
+ if (vindex == modrm_reg)
+ oappend ("/(bad)");
+ }
}
else if (intel_syntax)
{
else if (bytemode == v_bnd_mode
|| bytemode == v_bndmk_mode
|| bytemode == bnd_mode
- || bytemode == bnd_swap_mode)
+ || bytemode == bnd_swap_mode
+ || bytemode == vex_vsib_d_w_dq_mode
+ || bytemode == vex_vsib_q_w_dq_mode)
{
oappend ("(bad)");
return;
oappend (scratchbuf);
}
}
- if (vex.evex && vex.b
+ if (vex.b
&& (bytemode == x_mode
- || bytemode == xmmq_mode
|| bytemode == evex_half_bcst_xmmq_mode))
{
if (vex.w
- || bytemode == xmmq_mode
|| bytemode == evex_half_bcst_xmmq_mode)
{
switch (vex.length)
reg += 16;
}
- if (need_vex
- && bytemode != xmm_mode
- && bytemode != xmmq_mode
- && bytemode != evex_half_bcst_xmmq_mode
- && bytemode != ymm_mode
- && bytemode != tmm_mode
- && bytemode != scalar_mode)
- {
- switch (vex.length)
- {
- case 128:
- names = names_xmm;
- break;
- case 256:
- if (vex.w
- || (bytemode != vex_vsib_q_w_dq_mode
- && bytemode != vex_vsib_q_w_d_mode))
- names = names_ymm;
- else
- names = names_xmm;
- break;
- case 512:
- names = names_zmm;
- break;
- default:
- abort ();
- }
- }
- else if (bytemode == xmmq_mode
- || bytemode == evex_half_bcst_xmmq_mode)
+ if (bytemode == xmmq_mode
+ || bytemode == evex_half_bcst_xmmq_mode)
{
switch (vex.length)
{
abort ();
}
}
+ else if (bytemode == ymm_mode)
+ names = names_ymm;
else if (bytemode == tmm_mode)
{
modrm.reg = reg;
}
names = names_tmm;
}
- else if (bytemode == ymm_mode)
- names = names_ymm;
+ else if (need_vex
+ && bytemode != xmm_mode
+ && bytemode != scalar_mode)
+ {
+ switch (vex.length)
+ {
+ case 128:
+ names = names_xmm;
+ break;
+ case 256:
+ if (vex.w
+ || bytemode != vex_vsib_q_w_dq_mode)
+ names = names_ymm;
+ else
+ names = names_xmm;
+ break;
+ case 512:
+ if (vex.w
+ || bytemode != vex_vsib_q_w_dq_mode)
+ names = names_zmm;
+ else
+ names = names_ymm;
+ break;
+ default:
+ abort ();
+ }
+ }
else
names = names_xmm;
oappend (names[reg]);
static void
OP_VEX (int bytemode, int sizeflag ATTRIBUTE_UNUSED)
{
- int reg;
+ int reg, modrm_reg, sib_index = -1;
const char **names;
if (!need_vex)
else if (vex.evex && !vex.v)
reg += 16;
- if (bytemode == vex_scalar_mode)
+ switch (bytemode)
{
+ case vex_scalar_mode:
oappend (names_xmm[reg]);
return;
- }
- if (bytemode == tmm_mode)
- {
+ case vex_vsib_d_w_dq_mode:
+ case vex_vsib_q_w_dq_mode:
+ /* This must be the 3rd operand. */
+ if (obufp != op_out[2])
+ abort ();
+ if (vex.length == 128
+ || (bytemode != vex_vsib_d_w_dq_mode
+ && !vex.w))
+ oappend (names_xmm[reg]);
+ else
+ oappend (names_ymm[reg]);
+
+ /* All 3 XMM/YMM registers must be distinct. */
+ modrm_reg = modrm.reg;
+ if (rex & REX_R)
+ modrm_reg += 8;
+
+ if (modrm.rm == 4)
+ {
+ sib_index = sib.index;
+ if (rex & REX_X)
+ sib_index += 8;
+ }
+
+ if (reg == modrm_reg || reg == sib_index)
+ strcpy (obufp, "/(bad)");
+ if (modrm_reg == sib_index || modrm_reg == reg)
+ strcat (op_out[0], "/(bad)");
+ if (sib_index == modrm_reg || sib_index == reg)
+ strcat (op_out[1], "/(bad)");
+
+ return;
+
+ case tmm_mode:
/* All 3 TMM registers must be distinct. */
if (reg >= 8)
oappend ("(bad)");
switch (bytemode)
{
case vex_mode:
- case vex_vsib_q_w_dq_mode:
- case vex_vsib_q_w_d_mode:
names = names_xmm;
break;
case dq_mode:
case vex_mode:
names = names_ymm;
break;
- case vex_vsib_q_w_dq_mode:
- case vex_vsib_q_w_d_mode:
- names = vex.w ? names_ymm : names_xmm;
- break;
case mask_bd_mode:
case mask_mode:
if (reg > 0x7)