cosmopolitan/tool/build/lib/disspec.c

1115 lines
34 KiB
C
Raw Normal View History

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
2020-12-28 01:18:44 +00:00
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
2020-12-28 01:18:44 +00:00
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/str/str.h"
#include "third_party/xed/x86.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/modrm.h"
#define UNKNOWN "wut"
#define RCASE(x, y) CASE(x, return y)
static const char kFpuName[][8][8] = {
{"fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr"},
{"fchs", "fabs", UNKNOWN, UNKNOWN, "ftst", "fxam", UNKNOWN, UNKNOWN},
{"fld1", "fldl2t", "fldl2e", "fldpi", "fldlg2", "fldln2", "fldz"},
{"f2xm1", "fyl2x", "fptan", "fpatan", "fxtract", "fprem1", "fdecstp",
"fincstp"},
{"fprem", "fyl2xp1", "fsqrt", "fsincos", "frndint", "fscale", "fsin",
"fcos"},
{"fneni", "fndisi", "fnclex", "fninit", "fnsetpm"},
};
char *DisOpFpu1(struct XedDecodedInst *x, char *p, const char *extra) {
stpcpy(stpcpy(p, kFpuName[0][ModrmReg(x->op.rde)]), extra);
return p;
}
char *DisOp66(struct XedDecodedInst *x, char *p, const char *s, const char *a,
const char *b) {
stpcpy(stpcpy(p, s), !Osz(x->op.rde) ? a : b);
return p;
}
char *DisOpVpsWpsVssWss(struct XedDecodedInst *x, char *p, const char *s) {
return DisOp66(x, p, s, "ps %Vps Wps", "ss %Vss Wss");
}
char *DisOpVpdWpdVpsWps(struct XedDecodedInst *x, char *p, const char *s) {
return DisOp66(x, p, s, "ps %Vps Wps", "pd %Vpd Wpd");
}
char *DisOpPqQqVdqWdq(struct XedDecodedInst *x, char *p, const char *s) {
return DisOp66(x, p, s, " %Pq Qq", " %Vdq Wdq");
}
char *DisOpPqQqIbVdqWdqIb(struct XedDecodedInst *x, char *p, const char *s) {
return DisOp66(x, p, s, " %Pq Qq Ib", " %Vdq Wdq Ib");
}
char *DisOpNqIbUdqIb(struct XedDecodedInst *x, char *p, const char *s) {
return DisOp66(x, p, s, " %Nq Ib", " %Udq Ib");
}
char *DisOpVpsWpsVssWssVpdWpdVsdWsd(struct XedDecodedInst *x, char *p,
const char *s) {
char *q = stpcpy(p, s);
if (Rep(x->op.rde) == 3) {
stpcpy(q, "ss %Vss Wss");
} else if (Rep(x->op.rde) == 2) {
stpcpy(q, "sd %Vsd Wsd");
} else if (Osz(x->op.rde)) {
stpcpy(q, "pd %Vpd Wpd");
} else {
stpcpy(q, "ps %Vps Wps");
}
return p;
}
const char *DisSpecFpu0(struct XedDecodedInst *x, int group) {
const char *s;
s = kFpuName[group][ModrmRm(x->op.rde)];
return *s ? s : UNKNOWN;
}
const char *DisSpecRegMem(struct XedDecodedInst *x, const char *a,
const char *b) {
if (IsModrmRegister(x->op.rde)) {
return a;
} else {
return b;
}
}
const char *DisSpecRegMemFpu0(struct XedDecodedInst *x, int group,
const char *b) {
return DisSpecRegMem(x, DisSpecFpu0(x, group), b);
}
const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
switch (x->op.opcode & 0xff) {
RCASE(0x00, "ALU Eb %Gb");
RCASE(0x01, "ALU Evqp %Gvqp");
RCASE(0x02, "ALU %Gb Eb");
RCASE(0x03, "ALU %Gvqp Evqp");
RCASE(0x04, "ALU %al Ib");
RCASE(0x05, "ALU %rAX Ivds");
RCASE(0x06, "push %es");
RCASE(0x07, "pop %es");
RCASE(0x08, "ALU Eb %Gb");
RCASE(0x09, "ALU Evqp %Gvqp");
RCASE(0x0a, "ALU %Gb Eb");
RCASE(0x0b, "ALU %Gvqp Evqp");
RCASE(0x0c, "ALU %al Ib");
RCASE(0x0d, "ALU %rAX Ivds");
RCASE(0x0e, "push %cs");
RCASE(0x0f, "pop %cs");
RCASE(0x10, "ALU Eb %Gb");
RCASE(0x11, "ALU Evqp %Gvqp");
RCASE(0x12, "ALU %Gb Eb");
RCASE(0x13, "ALU %Gvqp Evqp");
RCASE(0x14, "ALU %al Ib");
RCASE(0x15, "ALU %rAX Ivds");
RCASE(0x16, "push %ss");
RCASE(0x17, "pop %ss");
RCASE(0x18, "ALU Eb %Gb");
RCASE(0x19, "ALU Evqp %Gvqp");
RCASE(0x1a, "ALU %Gb Eb");
RCASE(0x1b, "ALU %Gvqp Evqp");
RCASE(0x1c, "ALU %al Ib");
RCASE(0x1d, "ALU %rAX Ivds");
RCASE(0x1e, "push %ds");
RCASE(0x1f, "pop %ds");
RCASE(0x20, "ALU Eb %Gb");
RCASE(0x21, "ALU Evqp %Gvqp");
RCASE(0x22, "ALU %Gb Eb");
RCASE(0x23, "ALU %Gvqp Evqp");
RCASE(0x24, "ALU %al Ib");
RCASE(0x25, "ALU %rAX Ivds");
RCASE(0x26, "push %es");
RCASE(0x27, "pop %es");
RCASE(0x28, "ALU Eb %Gb");
RCASE(0x29, "ALU Evqp %Gvqp");
RCASE(0x2a, "ALU %Gb Eb");
RCASE(0x2b, "ALU %Gvqp Evqp");
RCASE(0x2c, "ALU %al Ib");
RCASE(0x2d, "ALU %rAX Ivds");
RCASE(0x2F, "das");
RCASE(0x30, "ALU Eb %Gb");
RCASE(0x31, "ALU Evqp %Gvqp");
RCASE(0x32, "ALU %Gb Eb");
RCASE(0x33, "ALU %Gvqp Evqp");
RCASE(0x34, "ALU %al Ib");
RCASE(0x35, "ALU %rAX Ivds");
RCASE(0x37, "aaa");
RCASE(0x38, "ALU Eb %Gb");
RCASE(0x39, "ALU Evqp %Gvqp");
RCASE(0x3A, "ALU %Gb Eb");
RCASE(0x3B, "ALU %Gvqp Evqp");
RCASE(0x3C, "ALU %al Ib");
RCASE(0x3D, "ALU %rAX Ivds");
RCASE(0x3F, "aas");
RCASE(0x40 ... 0x47, "inc %Zv");
RCASE(0x48 ... 0x4f, "dec %Zv");
RCASE(0x50 ... 0x57, "push %Zvq");
RCASE(0x58 ... 0x5f, "pop %Zvq");
RCASE(0x60, "pusha");
RCASE(0x61, "popa");
RCASE(0x62, "bound");
RCASE(0x63, "movslLQ %Gdqp Ed");
RCASE(0x68, "pushWQ Ivs");
RCASE(0x69, "imul %Gvqp Evqp Ivds");
RCASE(0x6A, "pushWQ Ibss");
RCASE(0x6B, "imul %Gvqp Evqp Ibs");
2020-12-01 11:43:40 +00:00
RCASE(0x6C, "insb Yb DX");
RCASE(0x6D, "insWL Yv DX");
RCASE(0x6E, "outsb DX Xb");
RCASE(0x6F, "outsWL DX Xv");
RCASE(0x70 ... 0x7f, "jCC Jbs");
RCASE(0x80, "ALU2 Eb Ib");
RCASE(0x81, "ALU2 Evqp Ivds");
RCASE(0x82, "ALU2 Eb Ib");
RCASE(0x83, "ALU2 Evqp Ibs");
RCASE(0x84, "test Eb %Gb");
RCASE(0x85, "test %Gvqp Evqp");
RCASE(0x86, "xchg %Gb Eb");
RCASE(0x87, "xchg %Gvqp Evqp");
RCASE(0x88, "mov Eb %Gb");
RCASE(0x89, "mov Evqp %Gvqp");
RCASE(0x8A, "mov %Gb Eb");
RCASE(0x8B, "mov %Gvqp Evqp");
RCASE(0x8C, "mov Evqp %Sw");
RCASE(0x8D, "lea %Gvqp M");
RCASE(0x8E, "mov %Sw Evqp");
RCASE(0x90, "nop");
RCASE(0x91 ... 0x97, "xchg %Zvqp %rAX");
RCASE(0x98, "cwtl");
RCASE(0x99, "cltd");
RCASE(0x9A, "lcall Pvds Kvds");
RCASE(0x9B, "fwait");
RCASE(0x9C, "pushfWQ");
RCASE(0x9D, "popfWQ");
RCASE(0x9E, "sahf");
RCASE(0x9F, "lahf");
RCASE(0xA0, "movABS %al Ob");
RCASE(0xA1, "movABS %rAX Ovqp");
RCASE(0xA2, "movABS Ob %al");
RCASE(0xA3, "movABS Ovqp %rAX");
RCASE(0xA4, "movsb Yb Xb");
RCASE(0xA5, "movsWLQ Yvqp Xvqp");
RCASE(0xA6, "cmpsb Yb Xb");
RCASE(0xA7, "cmpsWLQ Yvqp Xvqp");
RCASE(0xA8, "test %al Ib");
RCASE(0xA9, "test %rAX Ivds");
RCASE(0xAA, "stosb Yb %al");
RCASE(0xAB, "stosWLQ Yvqp %rAX");
RCASE(0xAC, "lodsb %al Xb");
RCASE(0xAD, "lodsWLQ %rAX Xvqp");
RCASE(0xAE, "scasb %al Yb");
RCASE(0xAF, "scasWLQ %rAX Yvqp");
RCASE(0xB0 ... 0xb7, "mov %Zb Ib");
RCASE(0xB8 ... 0xbf, "movABS %Zvqp Ivqp");
RCASE(0xC0, "BIT Eb Ib");
RCASE(0xC1, "BIT Evqp Ib");
RCASE(0xC2, "ret Iw");
RCASE(0xC3, "ret");
RCASE(0xC4, "les %Gv Mp");
RCASE(0xC5, "lds %Gv Mp");
RCASE(0xC6, "mov Eb Ib");
RCASE(0xC7, "mov Evqp Ivds");
RCASE(0xC9, "leave");
RCASE(0xCA, "lret Iw");
RCASE(0xCB, "lret");
RCASE(0xCC, "int3");
RCASE(0xCD, "int Ib");
RCASE(0xD0, "BIT Eb");
RCASE(0xD1, "BIT Evqp");
RCASE(0xD2, "BIT Evqp %cl");
RCASE(0xD3, "BIT Evqp %cl");
RCASE(0xD4, x->op.uimm0 == 0x0a ? "aam" : "aam Ib");
RCASE(0xD5, x->op.uimm0 == 0x0a ? "aad" : "aad Ib");
RCASE(0xD6, "salc");
RCASE(0xD7, "xlat BBb");
RCASE(0xE0, "loopne Jbs");
RCASE(0xE1, "loope Jbs");
RCASE(0xE2, "loop Jbs");
RCASE(0xE3, "jcxz Jbs");
RCASE(0xE4, "in %al Ib");
RCASE(0xE5, "in %eAX Ib");
RCASE(0xE6, "out Ib %al");
RCASE(0xE7, "out Ib %eAX");
RCASE(0xE8, "call Jvds");
RCASE(0xE9, "jmp Jvds");
RCASE(0xEA, "ljmp Rvds Kvds");
RCASE(0xEB, "jmp Jbs");
2020-12-01 11:43:40 +00:00
RCASE(0xEC, "in %al DX");
RCASE(0xED, "in %eAX DX");
RCASE(0xEE, "out DX %al");
RCASE(0xEF, "out DX %eAX");
RCASE(0xF1, "int1");
RCASE(0xF4, "hlt");
RCASE(0xF5, "cmc");
RCASE(0xF8, "clc");
RCASE(0xF9, "stc");
RCASE(0xFA, "cli");
RCASE(0xFB, "sti");
RCASE(0xFC, "cld");
RCASE(0xFD, "std");
case 0x8F:
switch (ModrmReg(x->op.rde)) {
RCASE(0, "popWQ Evq");
default:
break;
}
break;
case 0xD9:
switch (ModrmReg(x->op.rde)) {
RCASE(1, "fxch EST1");
RCASE(3, "fstps Msr %st");
RCASE(0, DisSpecRegMem(x, "fld EST", "flds Msr"));
RCASE(2, DisSpecRegMem(x, "fnop", "fsts Msr %st"));
RCASE(4, DisSpecRegMemFpu0(x, 1, "fldenv Me"));
RCASE(5, DisSpecRegMemFpu0(x, 2, "fldcw Mw"));
RCASE(6, DisSpecRegMemFpu0(x, 3, "fnstenv M"));
RCASE(7, DisSpecRegMemFpu0(x, 4, "fnstcw Mw"));
}
break;
case 0xDA:
switch (ModrmReg(x->op.rde)) {
RCASE(0, DisSpecRegMem(x, "fcmovb %st EST", "fiaddl Mdi"));
RCASE(1, DisSpecRegMem(x, "fcmove %st EST", "fimull Mdi"));
RCASE(2, DisSpecRegMem(x, "fcmovbe %st EST", "ficoml Mdi"));
RCASE(3, DisSpecRegMem(x, "fcmovu %st EST", "ficompl Mdi"));
RCASE(4, DisSpecRegMem(x, "fisubr Mdi", "fisubl Mdi"));
RCASE(5, DisSpecRegMem(x, "fucompp", "fisubrl Mdi"));
RCASE(6, DisSpecRegMem(x, "fidivl Mdi", "UNKNOWN"));
RCASE(7, DisSpecRegMem(x, "fidivrl Mdi", "UNKNOWN"));
}
break;
case 0xDB:
switch (ModrmReg(x->op.rde)) {
RCASE(0, DisSpecRegMem(x, "fcmovnb %st EST", "fildl Mdi"));
RCASE(1, DisSpecRegMem(x, "fcmovne %st EST", "fisttpl Mdi"));
RCASE(2, DisSpecRegMem(x, "fcmovnbe %st EST", "fistl Mdi"));
RCASE(3, DisSpecRegMem(x, "fcmovnu %st EST", "fistpl Mdi"));
RCASE(4, DisSpecFpu0(x, 5));
RCASE(5, DisSpecRegMem(x, "fucomi %st EST", "fldt Mer"));
RCASE(6, DisSpecRegMem(x, "fcomi %st EST", UNKNOWN));
RCASE(7, DisSpecRegMem(x, UNKNOWN, "fstpt Mer"));
}
break;
case 0xD8:
return DisOpFpu1(x, p, !IsModrmRegister(x->op.rde) ? "s Msr" : " EST1");
case 0xDC:
if (!IsModrmRegister(x->op.rde)) {
return DisOpFpu1(x, p, "l Mdr");
} else {
switch (ModrmReg(x->op.rde)) {
RCASE(0, "fadd EST %st");
RCASE(1, "fmul EST %st");
RCASE(2, "fcom %st EST");
RCASE(3, "fcomp %st EST");
RCASE(4, "fsub EST %st");
RCASE(5, "fsubr EST %st");
RCASE(6, "fdiv EST %st");
RCASE(7, "fdivr EST %st");
}
}
break;
case 0xDD:
if (!IsModrmRegister(x->op.rde)) {
switch (ModrmReg(x->op.rde)) {
RCASE(0, "fldl Mdr");
RCASE(1, "fisttpll Mqi");
RCASE(2, "fstl Mdr");
RCASE(3, "fstpl Mdr");
RCASE(4, "frstor Mdr");
RCASE(6, "fnsave Mst");
RCASE(7, "fnstsw Mst");
}
} else {
switch (ModrmReg(x->op.rde)) {
RCASE(0, "ffree EST");
RCASE(1, "fxch EST");
RCASE(2, "fst EST");
RCASE(3, "fstp EST");
RCASE(4, "fucom EST1");
RCASE(5, "fucomp EST1");
}
}
break;
case 0xDE:
if (!IsModrmRegister(x->op.rde)) {
switch (ModrmReg(x->op.rde)) {
RCASE(0, "fiadds Mwi");
RCASE(1, "fimuls Mwi");
RCASE(2, "ficoms Mwi");
RCASE(3, "ficomps Mwi");
RCASE(4, "fisubs Mwi");
RCASE(5, "fisubrs Mwi");
RCASE(6, "fidivs Mwi");
RCASE(7, "fidivrs Mwi");
}
} else {
switch (ModrmReg(x->op.rde)) {
RCASE(0, "faddp EST1");
RCASE(1, "fmulp EST1");
RCASE(2, "fcomp EST1");
RCASE(3, "fcompp");
RCASE(4, "fsubp EST1");
RCASE(5, "fsubrp EST1");
RCASE(6, "fdivp EST1");
RCASE(7, "fdivrp EST1");
}
}
break;
case 0xDF:
if (!IsModrmRegister(x->op.rde)) {
switch (ModrmReg(x->op.rde)) {
RCASE(0, "filds Mwi");
RCASE(1, "fisttps Mwi");
RCASE(2, "fists Mwi");
RCASE(3, "fistps Mwi");
RCASE(4, "fbld");
RCASE(5, "fildll Mqi");
RCASE(6, "fbstp");
RCASE(7, "fistpll Mqi");
}
} else {
switch (ModrmReg(x->op.rde)) {
RCASE(0, "ffreep EST");
RCASE(1, "fxch");
RCASE(2, "fstp EST");
RCASE(3, "fstp EST");
RCASE(4, "fnstsw");
RCASE(5, "fucomip EST");
RCASE(6, "fcomip EST");
}
}
break;
case 0xF6:
switch (ModrmReg(x->op.rde)) {
RCASE(0, "test Eb Ib");
RCASE(1, "test Eb Ib");
RCASE(2, "not Eb");
RCASE(3, "neg Eb");
RCASE(4, "mulb Eb");
RCASE(5, "imulb Eb");
RCASE(6, "divb Eb");
RCASE(7, "idivb Eb");
}
break;
case 0xF7:
switch (ModrmReg(x->op.rde)) {
RCASE(0, "test Evqp Ivds");
RCASE(1, "test Evqp Ivds");
RCASE(2, "not Evqp");
RCASE(3, "neg Evqp");
RCASE(4, "mul Evqp");
RCASE(5, "imul Evqp");
RCASE(6, "div Evqp");
RCASE(7, "idiv Evqp");
}
break;
case 0xFE:
switch (ModrmReg(x->op.rde)) {
RCASE(0, "inc Eb");
RCASE(1, "dec Eb");
}
break;
case 0xFF:
switch (ModrmReg(x->op.rde)) {
RCASE(0, "inc Evqp");
RCASE(1, "dec Evqp");
RCASE(2, "CALL Eq");
RCASE(4, "JMP Eq");
RCASE(6, "pushWQ Evq");
}
break;
}
return UNKNOWN;
}
const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
bool isreg;
isreg = IsModrmRegister(x->op.rde);
switch (x->op.opcode & 0xff) {
RCASE(0x02, "lar %Gvqp Ev");
RCASE(0x03, "lsl %Gvqp Ev");
RCASE(0x05, "syscall");
RCASE(0x0B, "ud2");
RCASE(0x0D, "nop Ev");
RCASE(0x18, "nop Ev");
RCASE(0x19, "nop Ev");
RCASE(0x1A, "nop Ev");
RCASE(0x1B, "nop Ev");
RCASE(0x1C, "nop Ev");
RCASE(0x1D, "nop Ev");
RCASE(0x20, "mov %Hd %Cd");
RCASE(0x22, "mov %Cd %Hd");
RCASE(0x28, "movapSD %Vps Wps");
RCASE(0x29, "movapSD Wps %Vps");
RCASE(0x2B, "movntpSD Mps %Vps");
RCASE(0x2E, Osz(x->op.rde) ? "ucomisd %Vsd Wsd" : "ucomiss %Vss Wss");
RCASE(0x2F, Osz(x->op.rde) ? "comisd %Vsd Wsd" : "comiss %Vss Wss");
RCASE(0x30, "wrmsr");
RCASE(0x31, "rdtsc");
RCASE(0x32, "rdmsr");
RCASE(0x33, "rdpmc");
RCASE(0x34, "sysenter");
RCASE(0x35, "sysexit");
RCASE(0x40 ... 0x4f, "cmovCC %Gvqp Evqp");
RCASE(0x52, DisOpVpsWpsVssWss(x, p, "rsqrt"));
RCASE(0x53, DisOpVpsWpsVssWss(x, p, "rcp"));
RCASE(0x54, DisOpVpdWpdVpsWps(x, p, "and"));
RCASE(0x55, DisOpVpdWpdVpsWps(x, p, "andn"));
RCASE(0x56, DisOpVpdWpdVpsWps(x, p, "or"));
RCASE(0x57, DisOpVpdWpdVpsWps(x, p, "xor"));
RCASE(0x58, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "add"));
RCASE(0x59, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "mul"));
RCASE(0x5C, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "sub"));
RCASE(0x5D, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "min"));
RCASE(0x5E, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "div"));
RCASE(0x5F, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "max"));
RCASE(0x60, DisOpPqQqVdqWdq(x, p, "punpcklbw"));
RCASE(0x61, DisOpPqQqVdqWdq(x, p, "punpcklwd"));
RCASE(0x62, DisOpPqQqVdqWdq(x, p, "punpckldq"));
RCASE(0x63, DisOpPqQqVdqWdq(x, p, "packsswb"));
RCASE(0x64, DisOpPqQqVdqWdq(x, p, "pcmpgtb"));
RCASE(0x65, DisOpPqQqVdqWdq(x, p, "pcmpgtw"));
RCASE(0x66, DisOpPqQqVdqWdq(x, p, "pcmpgtd"));
RCASE(0x67, DisOpPqQqVdqWdq(x, p, "packuswb"));
RCASE(0x68, DisOpPqQqVdqWdq(x, p, "punpckhbw"));
RCASE(0x69, DisOpPqQqVdqWdq(x, p, "punpckhwd"));
RCASE(0x6A, DisOpPqQqVdqWdq(x, p, "punpckhdq"));
RCASE(0x6B, DisOpPqQqVdqWdq(x, p, "packssdw"));
RCASE(0x6C, DisOpPqQqVdqWdq(x, p, "punpcklqdq"));
RCASE(0x6D, DisOpPqQqVdqWdq(x, p, "punpckhqdq"));
RCASE(0x74, DisOpPqQqVdqWdq(x, p, "pcmpeqb"));
RCASE(0x75, DisOpPqQqVdqWdq(x, p, "pcmpeqw"));
RCASE(0x76, DisOpPqQqVdqWdq(x, p, "pcmpeqd"));
RCASE(0x77, "emms");
RCASE(0x80 ... 0x8f, "jCC Jvds");
RCASE(0x90 ... 0x9f, "setCC Jvds");
RCASE(0xA0, "push %fs");
RCASE(0xA1, "pop %fs");
RCASE(0xA2, "cpuid");
RCASE(0xA3, "bt Evqp %Gvqp");
RCASE(0xA4, "shld Evqp %Gvqp Ib");
RCASE(0xA5, "shld Evqp %Gvqp %cl");
RCASE(0xA8, "push %gs");
RCASE(0xA9, "pop %gs");
RCASE(0xAB, "bts Evqp %Gvqp");
RCASE(0xAC, "shrd Evqp %Gvqp Ib");
RCASE(0xAD, "shrd Evqp %Gvqp %cl");
RCASE(0xAF, "imul %Gvqp Evqp");
RCASE(0xB0, "cmpxchg Eb %Gb");
RCASE(0xB1, "cmpxchg Evqp %Gvqp");
RCASE(0xB3, "btr Evqp %Gvqp");
RCASE(0xB6, "movzbWLQ %Gvqp Eb");
RCASE(0xB7, "movzwWLQ %Gvqp Ew");
RCASE(0xB9, "ud %Gvqp Evqp");
RCASE(0xBB, "btc Evqp %Gvqp");
RCASE(0xBE, "movsbWLQ %Gvqp Eb");
RCASE(0xBF, "movswWLQ %Gvqp Ew");
RCASE(0xC0, "xadd Eb %Gb");
RCASE(0xC1, "xadd Evqp %Gvqp");
RCASE(0xC2, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "cmp"));
RCASE(0xC3, "movnti Mdqp %Gdqp");
RCASE(0xC8 ... 0xCF, "bswap %Zvqp");
RCASE(0xD1, DisOpPqQqVdqWdq(x, p, "psrlw"));
RCASE(0xD2, DisOpPqQqVdqWdq(x, p, "psrld"));
RCASE(0xD3, DisOpPqQqVdqWdq(x, p, "psrlq"));
RCASE(0xD4, DisOpPqQqVdqWdq(x, p, "paddq"));
RCASE(0xD5, DisOpPqQqVdqWdq(x, p, "pmullw"));
RCASE(0xD7, Osz(x->op.rde) ? "pmovmskb %Gdqp %Udq" : "pmovmskb %Gdqp %Nq");
RCASE(0xD8, DisOpPqQqVdqWdq(x, p, "psubusb"));
RCASE(0xD9, DisOpPqQqVdqWdq(x, p, "psubusw"));
RCASE(0xDA, DisOpPqQqVdqWdq(x, p, "pminub"));
RCASE(0xDB, DisOpPqQqVdqWdq(x, p, "pand"));
RCASE(0xDC, DisOpPqQqVdqWdq(x, p, "paddusb"));
RCASE(0xDD, DisOpPqQqVdqWdq(x, p, "paddusw"));
RCASE(0xDE, DisOpPqQqVdqWdq(x, p, "pmaxub"));
RCASE(0xDF, DisOpPqQqVdqWdq(x, p, "pandn"));
RCASE(0xE0, DisOpPqQqVdqWdq(x, p, "pavgb"));
RCASE(0xE1, DisOpPqQqVdqWdq(x, p, "psrawv"));
RCASE(0xE2, DisOpPqQqVdqWdq(x, p, "psradv"));
RCASE(0xE3, DisOpPqQqVdqWdq(x, p, "pavgw"));
RCASE(0xE4, DisOpPqQqVdqWdq(x, p, "pmulhuw"));
RCASE(0xE5, DisOpPqQqVdqWdq(x, p, "pmulhw"));
RCASE(0xE7, Osz(x->op.rde) ? "movntdq Mdq %Vdq" : "movntq Mq %Pq");
RCASE(0xE8, DisOpPqQqVdqWdq(x, p, "psubsb"));
RCASE(0xE9, DisOpPqQqVdqWdq(x, p, "psubsw"));
RCASE(0xEA, DisOpPqQqVdqWdq(x, p, "pminsw"));
RCASE(0xEB, DisOpPqQqVdqWdq(x, p, "por"));
RCASE(0xEC, DisOpPqQqVdqWdq(x, p, "paddsb"));
RCASE(0xED, DisOpPqQqVdqWdq(x, p, "paddsw"));
RCASE(0xEE, DisOpPqQqVdqWdq(x, p, "pmaxsw"));
RCASE(0xEF, DisOpPqQqVdqWdq(x, p, "pxor"));
RCASE(0xF0, "lddqu %Vdq Mdq");
RCASE(0xF1, DisOpPqQqVdqWdq(x, p, "psllwv"));
RCASE(0xF2, DisOpPqQqVdqWdq(x, p, "pslldv"));
RCASE(0xF3, DisOpPqQqVdqWdq(x, p, "psllqv"));
RCASE(0xF4, DisOpPqQqVdqWdq(x, p, "pmuludq"));
RCASE(0xF5, DisOpPqQqVdqWdq(x, p, "pmaddwd"));
RCASE(0xF6, DisOpPqQqVdqWdq(x, p, "psadbw"));
RCASE(0xF8, DisOpPqQqVdqWdq(x, p, "psubb"));
RCASE(0xF9, DisOpPqQqVdqWdq(x, p, "psubw"));
RCASE(0xFA, DisOpPqQqVdqWdq(x, p, "psubd"));
RCASE(0xFB, DisOpPqQqVdqWdq(x, p, "psubq"));
RCASE(0xFC, DisOpPqQqVdqWdq(x, p, "paddb"));
RCASE(0xFD, DisOpPqQqVdqWdq(x, p, "paddw"));
RCASE(0xFE, DisOpPqQqVdqWdq(x, p, "paddd"));
RCASE(0xFF, "ud0 %Gvqp Evqp");
case 0xBC:
if (Rep(x->op.rde) == 3) {
return "tzcnt %Gvqp Evqp";
} else {
return "bsf %Gvqp Evqp";
}
case 0xBD:
if (Rep(x->op.rde) == 3) {
return "lzcnt %Gvqp Evqp";
} else {
return "bsr %Gvqp Evqp";
}
case 0x01:
switch (ModrmReg(x->op.rde)) {
case 0:
if (!isreg) {
return "sgdt Ms";
} else {
switch (ModrmRm(x->op.rde)) {
case 1:
return "vmcall";
case 2:
return "vmlaunch";
case 3:
return "vmresume";
case 4:
return "vmxoff";
default:
return UNKNOWN;
}
}
break;
case 1:
if (!isreg) {
return "sidt Ms";
} else {
switch (ModrmRm(x->op.rde)) {
case 0:
return "monitor";
case 1:
return "mwait";
default:
return UNKNOWN;
}
}
break;
case 2:
if (!isreg) {
return "lgdt Ms";
} else if (ModrmRm(x->op.rde) == 0) {
return "xgetbv";
} else if (ModrmRm(x->op.rde) == 1) {
return "xsetbv";
} else {
return UNKNOWN;
}
break;
case 3:
if (!isreg) {
return "lidt Ms";
} else {
return UNKNOWN;
}
case 4:
return "smsw Ew";
case 6:
return "lmsw Ew";
case 7:
if (!isreg) {
return "invlpg M";
} else {
switch (ModrmRm(x->op.rde)) {
case 0:
return "swapgs";
case 1:
return "rdtscp";
default:
return UNKNOWN;
}
}
default:
return UNKNOWN;
}
case 0x1F:
if (ModrmMod(x->op.rde) == 1 && ModrmReg(x->op.rde) == 0 &&
ModrmRm(x->op.rde) == 0b101) {
return "bofram Jb";
} else {
return "nop Ev";
}
break;
case 0x70:
switch (Rep(x->op.rde) | Osz(x->op.rde)) {
RCASE(0, "pshufw %Pq Qq Ib");
RCASE(1, "pshufd %Vdq Wdq Ib");
RCASE(2, "pshuflw %Vdq Wdq Ib");
RCASE(3, "pshufhw %Vdq Wdq Ib");
}
break;
case 0x71:
switch (ModrmReg(x->op.rde)) {
RCASE(2, DisOpNqIbUdqIb(x, p, "psrlw"));
RCASE(4, DisOpNqIbUdqIb(x, p, "psraw"));
RCASE(6, DisOpNqIbUdqIb(x, p, "psllw"));
}
break;
case 0x72:
switch (ModrmReg(x->op.rde)) {
RCASE(2, DisOpNqIbUdqIb(x, p, "psrld"));
RCASE(4, DisOpNqIbUdqIb(x, p, "psrad"));
RCASE(6, DisOpNqIbUdqIb(x, p, "pslld"));
}
break;
case 0x73:
switch (ModrmReg(x->op.rde)) {
RCASE(2, DisOpNqIbUdqIb(x, p, "psrlq"));
RCASE(3, DisOpNqIbUdqIb(x, p, "psrldq"));
RCASE(6, DisOpNqIbUdqIb(x, p, "psllq"));
RCASE(7, DisOpNqIbUdqIb(x, p, "pslldq"));
}
break;
case 0xAE:
switch (ModrmReg(x->op.rde)) {
case 0:
if (isreg) {
return "rdfsbase %Rdqp";
} else {
return "fxsave M";
}
case 1:
if (isreg) {
return "rdgsbase %Rdqp";
} else {
return "fxrstor M";
}
case 2:
if (isreg) {
return "wrfsbase %Rdqp";
} else {
return "ldmxcsr Md";
}
case 3:
if (isreg) {
return "wrgsbase %Rdqp";
} else {
return "stmxcsr Md";
}
case 4:
if (isreg) {
return UNKNOWN;
} else {
return "xsave M %edx %eax";
}
case 5:
return "lfence";
case 6:
return "mfence";
case 7:
if (isreg && ModrmReg(x->op.rde) == 0b111) {
return "sfence";
} else {
return "clflush";
}
}
break;
case 0xBA:
switch (ModrmReg(x->op.rde)) {
RCASE(4, "btWLQ Evqp Ib");
RCASE(5, "btsWLQ Evqp Ib");
RCASE(6, "btrWLQ Evqp Ib");
RCASE(7, "btcWLQ Evqp Ib");
}
break;
case 0x10:
if (Rep(x->op.rde) == 3) {
return "movss %Vss Wss";
} else if (Rep(x->op.rde) == 2) {
return "movsd %Vsd Wsd";
} else if (Osz(x->op.rde)) {
return "movupd %Vpd Wpd";
} else {
return "movups %Vps Wps";
}
break;
case 0x11:
if (Rep(x->op.rde) == 3) {
return "movss Wss %Vss";
} else if (Rep(x->op.rde) == 2) {
return "movsd Wsd %Vsd";
} else if (Osz(x->op.rde)) {
return "movupd Wpd %Vpd";
} else {
return "movups Wps %Vps";
}
break;
case 0xC4:
if (!Osz(x->op.rde)) {
if (isreg) {
return "pinsrw %Pq %Rdqp Ib";
} else {
return "pinsrw %Pq Mw Ib";
}
} else {
if (isreg) {
return "pinsrw %Vdq %Rdqp Ib";
} else {
return "pinsrw %Vdq Mw Ib";
}
}
break;
case 0xC5:
if (!Osz(x->op.rde)) {
return "pextrw %Gdqp %Nq Ib";
} else {
return "pextrw %Gdqp %Udq Ib";
}
break;
case 0xC6:
if (!Osz(x->op.rde)) {
return "shufps %Vps Wps Ib";
} else {
return "shufpd %Vpd Wpd Ib";
}
break;
case 0xC7:
switch (ModrmReg(x->op.rde)) {
case 1:
if (!isreg) {
if (Rexw(x->op.rde)) {
return "cmpxchg16b Mdq";
} else {
return "cmpxchg8b Mq";
}
} else {
return UNKNOWN;
}
break;
case 6:
if (isreg) {
return "rdrand %Rdqp";
} else {
return UNKNOWN;
}
break;
case 7:
if (isreg) {
if (Rep(x->op.rde) == 3) {
return "rdpid %Rdqp";
} else {
return "rdseed %Rdqp";
}
} else {
return UNKNOWN;
}
break;
default:
return UNKNOWN;
}
break;
case 0xD6:
if (Osz(x->op.rde)) {
return "movq Wq %Vq";
} else if (Rep(x->op.rde) == 3) {
return "movq2dq %Vdq %Nq";
} else if (Rep(x->op.rde) == 2) {
return "movq2dq %Pq %Uq";
}
break;
case 0x12:
switch (Rep(x->op.rde) | Osz(x->op.rde)) {
case 0:
if (isreg) {
return "movhlps %Vq %Uq";
} else {
return "movlps %Vq Mq";
}
break;
case 1:
return "movlpd %Vq Mq";
case 2:
return "movddup %Vq Wq";
case 3:
return "movsldup %Vq Wq";
default:
unreachable;
}
break;
case 0x13:
if (Osz(x->op.rde)) {
return "movlpd Mq %Vq";
} else {
return "movlps Mq %Vq";
}
break;
case 0x16:
switch (Rep(x->op.rde) | Osz(x->op.rde)) {
case 0:
if (isreg) {
return "movlhps %Vq %Uq";
} else {
return "movhps %Vq Mq";
}
break;
case 1:
return "movhpd %Vq Mq";
case 3:
return "movshdup %Vq Wq";
default:
break;
}
break;
case 0x17:
if (Osz(x->op.rde)) {
return "movhpd Mq %Vq";
} else {
return "movhps Mq %Vq";
}
break;
case 0x2A:
if (Rep(x->op.rde) == 3) {
return "cvtsi2ss %Vss Edqp";
} else if (Rep(x->op.rde) == 2) {
return "cvtsi2sd %Vsd Edqp";
} else if (Osz(x->op.rde)) {
return "cvtpi2pd %Vpd Qpi";
} else {
return "cvtpi2ps %Vps Qpi";
}
break;
case 0x2C:
if (Rep(x->op.rde) == 3) {
return "cvttss2si %Gdqp Wss";
} else if (Rep(x->op.rde) == 2) {
return "cvttsd2si %Gdqp Wsd";
} else if (Osz(x->op.rde)) {
return "cvttpd2pi %Ppi Wpd";
} else {
return "cvttps2pi %Ppi Wpsq";
}
break;
case 0x2D:
if (Rep(x->op.rde) == 3) {
return "cvtss2si %Gdqp Wss";
} else if (Rep(x->op.rde) == 2) {
return "cvtsd2si %Gdqp Wsd";
} else if (Osz(x->op.rde)) {
return "cvtpd2pi %Ppi Wpd";
} else {
return "cvtps2pi %Ppi Wpsq";
}
break;
case 0x5a:
if (Rep(x->op.rde) == 3) {
return "cvtss2sd %Vsd Wss";
} else if (Rep(x->op.rde) == 2) {
return "cvtsd2ss %Vss Wsd";
} else if (Osz(x->op.rde)) {
return "cvtpd2ps %Vps Wpd";
} else {
return "cvtps2pd %Vpd Wps";
}
break;
case 0x5b:
if (Rep(x->op.rde) == 3) {
return "cvttps2dq %Vdq Wps";
} else if (Osz(x->op.rde)) {
return "cvtps2dq %Vdq Wps";
} else {
return "cvtdq2ps %Vps Wdq";
}
break;
case 0x51:
if (Rep(x->op.rde) == 3) {
return "sqrtss %Vss Wss";
} else if (Rep(x->op.rde) == 2) {
return "sqrtsd %Vsd Wsd";
} else if (Osz(x->op.rde)) {
return "sqrtpd %Vpd Wpd";
} else {
return "sqrtps %Vps Wps";
}
break;
case 0x6E:
if (Osz(x->op.rde)) {
if (Rexw(x->op.rde)) {
return "movq %Vdq Eqp";
} else {
return "movd %Vdq Ed";
}
} else {
if (Rexw(x->op.rde)) {
return "movq %Pq Eqp";
} else {
return "movd %Pq Ed";
}
}
break;
case 0x6F:
if (Rep(x->op.rde) == 3) {
return "movdqu %Vdq Wdq";
} else if (Osz(x->op.rde)) {
return "movdqa %Vdq Wdq";
} else {
return "movq %Pq Qq";
}
break;
case 0x7E:
if (Rep(x->op.rde) == 3) {
return "movq %Vq Wq";
} else if (Osz(x->op.rde)) {
if (Rexw(x->op.rde)) {
return "movq Eqp %Vdq";
} else {
return "movd Ed %Vdq";
}
} else {
if (Rexw(x->op.rde)) {
return "movq Eqp %Pq";
} else {
return "movd Ed %Pq";
}
}
break;
case 0x7F:
if (Rep(x->op.rde) == 3) {
return "movdqu Wdq %Vdq";
} else if (Osz(x->op.rde)) {
return "movdqa Wdq %Vdq";
} else {
return "movq Qq %Pq";
}
break;
case 0xE6:
if (Rep(x->op.rde) == 2) {
return "cvtpd2dq %Vdq Wpd";
} else if (Osz(x->op.rde)) {
return "cvttpd2dq %Vdq Wpd";
} else if (Rep(x->op.rde) == 3) {
return "cvtdq2pd %Vpd Wdq";
}
break;
}
return UNKNOWN;
}
const char *DisSpecMap2(struct XedDecodedInst *x, char *p) {
switch (x->op.opcode & 0xff) {
RCASE(0x00, DisOpPqQqVdqWdq(x, p, "pshufb"));
RCASE(0x01, DisOpPqQqVdqWdq(x, p, "phaddw"));
RCASE(0x02, DisOpPqQqVdqWdq(x, p, "phaddd"));
RCASE(0x03, DisOpPqQqVdqWdq(x, p, "phaddsw"));
RCASE(0x04, DisOpPqQqVdqWdq(x, p, "pmaddubsw"));
RCASE(0x05, DisOpPqQqVdqWdq(x, p, "phsubw"));
RCASE(0x06, DisOpPqQqVdqWdq(x, p, "phsubd"));
RCASE(0x07, DisOpPqQqVdqWdq(x, p, "phsubsw"));
RCASE(0x08, DisOpPqQqVdqWdq(x, p, "psignb"));
RCASE(0x09, DisOpPqQqVdqWdq(x, p, "psignw"));
RCASE(0x0A, DisOpPqQqVdqWdq(x, p, "psignd"));
RCASE(0x0B, DisOpPqQqVdqWdq(x, p, "pmulhrsw"));
RCASE(0x10, "pblendvb %Vdq Wdq");
RCASE(0x14, "blendvps Vps Wps");
RCASE(0x15, "blendvpd Vpd Wpd");
RCASE(0x17, "ptest %Vdq Wdq");
RCASE(0x1C, DisOpPqQqVdqWdq(x, p, "pabsb"));
RCASE(0x1D, DisOpPqQqVdqWdq(x, p, "pabsw"));
RCASE(0x1E, DisOpPqQqVdqWdq(x, p, "pabsd"));
RCASE(0x20, "pmovsxbw %Vdq Mq");
RCASE(0x21, "pmovsxbd %Vdq Md");
RCASE(0x22, "pmovsxbq %Vdq Mw");
RCASE(0x23, "pmovsxwd %Vdq Mq");
RCASE(0x24, "pmovsxwq %Vdq Md");
RCASE(0x25, "pmovsxdq %Vdq Mq");
RCASE(0x28, "pmuldq %Vdq Wdq");
RCASE(0x29, "pcmpeqq %Vdq Wdq");
RCASE(0x2A, "movntdqa %Vdq Mdq");
RCASE(0x2B, "packusdw %Vdq Wdq");
RCASE(0x30, "pmovzxbw %Vdq Mq");
RCASE(0x31, "pmovzxbd %Vdq Md");
RCASE(0x32, "pmovzxbq %Vdq Mw");
RCASE(0x33, "pmovzxwd %Vdq Mq");
RCASE(0x34, "pmovzxwq %Vdq Md");
RCASE(0x35, "pmovzxdq %Vdq Mq");
RCASE(0x37, "pcmpgtq %Vdq Wdq");
RCASE(0x38, "pminsb %Vdq Wdq");
RCASE(0x39, "pminsd %Vdq Wdq");
RCASE(0x3A, "pminuw %Vdq Wdq");
RCASE(0x3B, "pminud %Vdq Wdq");
RCASE(0x3C, "pmaxsb %Vdq Wdq");
RCASE(0x3D, "pmaxsd %Vdq Wdq");
RCASE(0x3E, "pmaxuw %Vdq Wdq");
RCASE(0x3F, "pmaxud %Vdq Wdq");
RCASE(0x40, "pmulld %Vdq Wdq");
RCASE(0x41, "phminposuw %Vdq Wdq");
RCASE(0x80, "invept %Gq Mdq");
RCASE(0x81, "invvpid %Gq Mdq");
case 0xF0:
if (Rep(x->op.rde) == 2) {
return "crc32 %Gvqp Eb";
} else {
return "movbe %Gvqp M";
}
break;
case 0xF1:
if (Rep(x->op.rde) == 2) {
return "crc32 %Gvqp Evqp";
} else {
return "movbe M %Gvqp";
}
break;
default:
return UNKNOWN;
}
}
const char *DisSpecMap3(struct XedDecodedInst *x, char *p) {
switch (x->op.opcode & 0xff) {
RCASE(0x0F, DisOpPqQqIbVdqWdqIb(x, p, "palignr"));
default:
return UNKNOWN;
}
}
const char *DisSpec(struct XedDecodedInst *x, char *p) {
switch (x->op.map & 7) {
case XED_ILD_MAP0:
return DisSpecMap0(x, p);
case XED_ILD_MAP1:
return DisSpecMap1(x, p);
case XED_ILD_MAP2:
return DisSpecMap2(x, p);
case XED_ILD_MAP3:
return DisSpecMap3(x, p);
default:
return UNKNOWN;
}
}