cosmopolitan/tool/build/lib/disspec.c

1105 lines
34 KiB
C

/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#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");
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");
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(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(0xBC, "bsf %Gvqp Evqp");
RCASE(0xBD, "bsr %Gvqp Evqp");
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 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;
}
}