static void OP_VMX (int, int);
static void OP_0fae (int, int);
static void OP_0f07 (int, int);
-static void NOP_Fixup (int, int);
+static void NOP_Fixup1 (int, int);
+static void NOP_Fixup2 (int, int);
static void OP_3DNowSuffix (int, int);
static void OP_SIMD_Suffix (int, int);
static void SIMD_Fixup (int, int);
static void BadOp (void);
static void SEG_Fixup (int, int);
static void VMX_Fixup (int, int);
+static void REP_Fixup (int, int);
struct dis_private {
/* Points to first byte not fetched. */
#define eSI OP_IMREG, eSI_reg
#define eDI OP_IMREG, eDI_reg
#define AL OP_IMREG, al_reg
-#define AL OP_IMREG, al_reg
#define CL OP_IMREG, cl_reg
#define DL OP_IMREG, dl_reg
#define BL OP_IMREG, bl_reg
#define OPSUF OP_3DNowSuffix, 0
#define OPSIMD OP_SIMD_Suffix, 0
+/* Used handle "rep" prefix for string instructions. */
+#define Xbr REP_Fixup, eSI_reg
+#define Xvr REP_Fixup, eSI_reg
+#define Ybr REP_Fixup, eDI_reg
+#define Yvr REP_Fixup, eDI_reg
+#define indirDXr REP_Fixup, indir_dx_reg
+#define ALr REP_Fixup, al_reg
+#define eAXr REP_Fixup, eAX_reg
+
#define cond_jump_flag NULL, cond_jump_mode
#define loop_jcxz_flag NULL, loop_jcxz_mode
#define USE_GROUPS 2
#define USE_PREFIX_USER_TABLE 3
#define X86_64_SPECIAL 4
+#define IS_3BYTE_OPCODE 5
#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0
#define GRP7 NULL, NULL, USE_GROUPS, NULL, 14, NULL, 0
#define GRP8 NULL, NULL, USE_GROUPS, NULL, 15, NULL, 0
#define GRP9 NULL, NULL, USE_GROUPS, NULL, 16, NULL, 0
-#define GRP10 NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0
-#define GRP11 NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0
-#define GRP12 NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0
-#define GRP13 NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0
-#define GRP14 NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0
+#define GRP12 NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0
+#define GRP13 NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0
+#define GRP14 NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0
+#define GRP15 NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0
+#define GRP16 NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0
#define GRPAMD NULL, NULL, USE_GROUPS, NULL, 22, NULL, 0
#define GRPPADLCK1 NULL, NULL, USE_GROUPS, NULL, 23, NULL, 0
#define GRPPADLCK2 NULL, NULL, USE_GROUPS, NULL, 24, NULL, 0
#define X86_64_0 NULL, NULL, X86_64_SPECIAL, NULL, 0, NULL, 0
+#define THREE_BYTE_0 NULL, NULL, IS_3BYTE_OPCODE, NULL, 0, NULL, 0
+#define THREE_BYTE_1 NULL, NULL, IS_3BYTE_OPCODE, NULL, 1, NULL, 0
+
typedef void (*op_rtn) (int bytemode, int sizeflag);
struct dis386 {
{ "imulS", Gv, Ev, Iv },
{ "pushT", sIb, XX, XX },
{ "imulS", Gv, Ev, sIb },
- { "ins{b||b|}", Yb, indirDX, XX },
- { "ins{R||R|}", Yv, indirDX, XX },
- { "outs{b||b|}", indirDX, Xb, XX },
- { "outs{R||R|}", indirDX, Xv, XX },
+ { "ins{b||b|}", Ybr, indirDX, XX },
+ { "ins{R||R|}", Yvr, indirDX, XX },
+ { "outs{b||b|}", indirDXr, Xb, XX },
+ { "outs{R||R|}", indirDXr, Xv, XX },
/* 70 */
{ "joH", Jb, XX, cond_jump_flag },
{ "jnoH", Jb, XX, cond_jump_flag },
{ "movQ", Sw, Sv, XX },
{ "popU", stackEv, XX, XX },
/* 90 */
- { "nop", NOP_Fixup, 0, XX, XX },
+ { "xchgS", NOP_Fixup1, eAX_reg, NOP_Fixup2, eAX_reg, XX },
{ "xchgS", RMeCX, eAX, XX },
{ "xchgS", RMeDX, eAX, XX },
{ "xchgS", RMeBX, eAX, XX },
{ "movS", eAX, Ov, XX },
{ "movB", Ob, AL, XX },
{ "movS", Ov, eAX, XX },
- { "movs{b||b|}", Yb, Xb, XX },
- { "movs{R||R|}", Yv, Xv, XX },
+ { "movs{b||b|}", Ybr, Xb, XX },
+ { "movs{R||R|}", Yvr, Xv, XX },
{ "cmps{b||b|}", Xb, Yb, XX },
{ "cmps{R||R|}", Xv, Yv, XX },
/* a8 */
{ "testB", AL, Ib, XX },
{ "testS", eAX, Iv, XX },
- { "stosB", Yb, AL, XX },
- { "stosS", Yv, eAX, XX },
- { "lodsB", AL, Xb, XX },
- { "lodsS", eAX, Xv, XX },
+ { "stosB", Ybr, AL, XX },
+ { "stosS", Yvr, eAX, XX },
+ { "lodsB", ALr, Xb, XX },
+ { "lodsS", eAXr, Xv, XX },
{ "scasB", AL, Yb, XX },
{ "scasS", eAX, Yv, XX },
/* b0 */
{ PREGRP31 },
{ "movhpX", EX, XM, SIMD_Fixup, 'l' },
/* 18 */
- { GRP14 },
- { "(bad)", XX, XX, XX },
+ { GRP16 },
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
+ { "nopQ", Ev, XX, XX },
/* 20 */
{ "movZ", Rm, Cm, XX },
{ "movZ", Rm, Dm, XX },
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
/* 38 */
+ { THREE_BYTE_0 },
{ "(bad)", XX, XX, XX },
- { "(bad)", XX, XX, XX },
- { "(bad)", XX, XX, XX },
+ { THREE_BYTE_1 },
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ PREGRP19 },
/* 70 */
{ PREGRP22 },
- { GRP10 },
- { GRP11 },
{ GRP12 },
+ { GRP13 },
+ { GRP14 },
{ "pcmpeqb", MX, EM, XX },
{ "pcmpeqw", MX, EM, XX },
{ "pcmpeqd", MX, EM, XX },
{ "btsS", Ev, Gv, XX },
{ "shrdS", Ev, Gv, Ib },
{ "shrdS", Ev, Gv, CL },
- { GRP13 },
+ { GRP15 },
{ "imulS", Gv, Ev, XX },
/* b0 */
{ "cmpxchgB", Eb, Gb, XX },
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* ------------------------------- */
/* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */
- /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */
+ /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1, /* 1f */
/* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */
- /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+ /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */
/* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */
/* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */
/* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */
/* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
/* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */
/* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */
- /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+ /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */
/* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
/* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */
/* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */
},
/* GRP7 */
{
- { "sgdtIQ", VMX_Fixup, 0, XX, XX },
- { "sidtIQ", PNI_Fixup, 0, XX, XX },
+ { "sgdt{Q|IQ||}", VMX_Fixup, 0, XX, XX },
+ { "sidt{Q|IQ||}", PNI_Fixup, 0, XX, XX },
{ "lgdt{Q|Q||}", M, XX, XX },
{ "lidt{Q|Q||}", SVME_Fixup, 0, XX, XX },
{ "smswQ", Ev, XX, XX },
{ "", VM, XX, XX }, /* See OP_VMX. */
{ "vmptrst", Eq, XX, XX },
},
- /* GRP10 */
+ /* GRP12 */
{
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ "psllw", MS, Ib, XX },
{ "(bad)", XX, XX, XX },
},
- /* GRP11 */
+ /* GRP13 */
{
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ "pslld", MS, Ib, XX },
{ "(bad)", XX, XX, XX },
},
- /* GRP12 */
+ /* GRP14 */
{
{ "(bad)", XX, XX, XX },
{ "(bad)", XX, XX, XX },
{ "psllq", MS, Ib, XX },
{ "pslldq", MS, Ib, XX },
},
- /* GRP13 */
+ /* GRP15 */
{
{ "fxsave", Ev, XX, XX },
{ "fxrstor", Ev, XX, XX },
{ "mfence", OP_0fae, 0, XX, XX },
{ "clflush", OP_0fae, 0, XX, XX },
},
- /* GRP14 */
+ /* GRP16 */
{
{ "prefetchnta", Ev, XX, XX },
{ "prefetcht0", Ev, XX, XX },
},
};
+static const struct dis386 three_byte_table[][32] = {
+ /* THREE_BYTE_0 */
+ {
+ { "pshufb", MX, EM, XX },
+ { "phaddw", MX, EM, XX },
+ { "phaddd", MX, EM, XX },
+ { "phaddsw", MX, EM, XX },
+ { "pmaddubsw", MX, EM, XX },
+ { "phsubw", MX, EM, XX },
+ { "phsubd", MX, EM, XX },
+ { "phsubsw", MX, EM, XX },
+ { "psignb", MX, EM, XX },
+ { "psignw", MX, EM, XX },
+ { "psignd", MX, EM, XX },
+ { "pmulhrsw", MX, EM, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "pabsb", MX, EM, XX },
+ { "pabsw", MX, EM, XX },
+ { "pabsd", MX, EM, XX },
+ { "(bad)", XX, XX, XX }
+ },
+ /* THREE_BYTE_1 */
+ {
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "palignr", MX, EM, Ib },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX }
+ },
+};
+
#define INTERNAL_DISASSEMBLER_ERROR _("<internal disassembler error>")
static void
}
}
- if (need_modrm)
+ if (dp->name == NULL && dp->bytemode1 == IS_3BYTE_OPCODE)
+ {
+ FETCH_DATA (info, codep + 2);
+ dp = &three_byte_table[dp->bytemode2][*codep++];
+ mod = (*codep >> 6) & 3;
+ reg = (*codep >> 3) & 7;
+ rm = *codep & 7;
+ }
+ else if (need_modrm)
{
FETCH_DATA (info, codep + 1);
mod = (*codep >> 6) & 3;
OP_E (bytemode, sizeflag);
}
+/* NOP is an alias of "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in
+ 32bit mode and "xchg %rax,%rax" in 64bit mode. NOP with REPZ prefix
+ is called PAUSE. We display "xchg %ax,%ax" instead of "data16 nop".
+ */
+
static void
-NOP_Fixup (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+NOP_Fixup1 (int bytemode, int sizeflag)
{
- /* NOP with REPZ prefix is called PAUSE. */
if (prefixes == PREFIX_REPZ)
strcpy (obuf, "pause");
+ else if (prefixes == PREFIX_DATA
+ || ((rex & REX_MODE64) && rex != 0x48))
+ OP_REG (bytemode, sizeflag);
+ else
+ strcpy (obuf, "nop");
+}
+
+static void
+NOP_Fixup2 (int bytemode, int sizeflag)
+{
+ if (prefixes == PREFIX_DATA
+ || ((rex & REX_MODE64) && rex != 0x48))
+ OP_IMREG (bytemode, sizeflag);
}
static const char *const Suffix3DNow[] = {
strcpy (obuf, "vmptrld");
OP_E (bytemode, sizeflag);
}
+
+static void
+REP_Fixup (int bytemode, int sizeflag)
+{
+ /* The 0xf3 prefix should be displayed as "rep" for ins, outs, movs,
+ lods and stos. */
+ size_t ilen = 0;
+
+ if (prefixes & PREFIX_REPZ)
+ switch (*insn_codep)
+ {
+ case 0x6e: /* outsb */
+ case 0x6f: /* outsw/outsl */
+ case 0xa4: /* movsb */
+ case 0xa5: /* movsw/movsl/movsq */
+ if (!intel_syntax)
+ ilen = 5;
+ else
+ ilen = 4;
+ break;
+ case 0xaa: /* stosb */
+ case 0xab: /* stosw/stosl/stosq */
+ case 0xac: /* lodsb */
+ case 0xad: /* lodsw/lodsl/lodsq */
+ if (!intel_syntax && (sizeflag & SUFFIX_ALWAYS))
+ ilen = 5;
+ else
+ ilen = 4;
+ break;
+ case 0x6c: /* insb */
+ case 0x6d: /* insl/insw */
+ if (!intel_syntax)
+ ilen = 4;
+ else
+ ilen = 3;
+ break;
+ default:
+ abort ();
+ break;
+ }
+
+ if (ilen != 0)
+ {
+ size_t olen;
+ char *p;
+
+ olen = strlen (obuf);
+ p = obuf + olen - ilen - 1 - 4;
+ /* Handle "repz [addr16|addr32]". */
+ if ((prefixes & PREFIX_ADDR))
+ p -= 1 + 6;
+
+ memmove (p + 3, p + 4, olen - (p + 3 - obuf));
+ }
+
+ switch (bytemode)
+ {
+ case al_reg:
+ case eAX_reg:
+ case indir_dx_reg:
+ OP_IMREG (bytemode, sizeflag);
+ break;
+ case eDI_reg:
+ OP_ESreg (bytemode, sizeflag);
+ break;
+ case eSI_reg:
+ OP_DSreg (bytemode, sizeflag);
+ break;
+ default:
+ abort ();
+ break;
+ }
+}