dis_tables.c revision e007031558dddc1a7f3593d9457d99bde738653e
#
pragma ident "%Z%%M% %I% %E% SMI" * Disassembly begins in dis_distable, which is equivalent to the One-byte * Opcode Map in the Intel IA32 ISA Reference (page A-6 in my copy). The * decoding loops then traverse out through the other tables as necessary to * decode a given instruction. * The behavior of this file can be controlled by one of the following flags: * DIS_TEXT Include text for disassembly * DIS_MEM Include memory-size calculations * Either or both of these can be defined. * This file is not, and will never be, cstyled. If anything, the tables should * be taken out another tab stop or two so nothing overlaps. * These functions must be provided for the consumer to do disassembly. extern int strcmp(
const char *,
const char *);
#
define TERM 0
/* used to indicate that the 'indirect' */ /* field terminates - no pointer. */ /* Used to decode instructions. */ M,
/* register or memory */ Mb,
/* register or memory, always byte sized */ MO,
/* memory only (no registers) */ DSHIFT,
/* for double shift that has an 8-bit immediate */ NORM,
/* instructions w/o ModR/M byte, no memory access */ IMPLMEM,
/* instructions w/o ModR/M byte, implicit mem access */ IMUL,
/* for 186 iimul instr */ CBW,
/* so data16 can be evaluated for cbw and variants */ MvI,
/* for 186 logicals */ ENTER,
/* for 186 enter instr */ RMw,
/* for 286 arpl instr */ Ib,
/* for push immediate byte */ F,
/* for 287 instructions */ FF,
/* for 287 instructions */ FFC,
/* for 287 instructions */ LSEG,
/* for 3-bit seg reg encoding */ MIb,
/* for 386 logicals */ SREG,
/* for 386 special registers */ PREFIX,
/* a REP instruction prefix */ LOCK,
/* a LOCK instruction prefix */ INT3,
/* The int 3 instruction, which has a fake operand */ INTx,
/* The normal int instruction, with explicit int num */ DSHIFTcl,
/* for double shift that implicitly uses %cl */ CWD,
/* so data16 can be evaluated for cwd and variants */ RET,
/* single immediate 16-bit operand */ MOVZ,
/* for movs and movz, with different size operands */ MOVSXZ,
/* AMD64 mov sign extend 32 to 64 bit instruction */ MMOSH,
/* Prefixable MMX mm,imm8 */ XMMOX3,
/* Prefixable SIMD xmm -> r32 */ XMMOM,
/* Prefixable SIMD xmm -> mem */ XMMOMS,
/* Prefixable SIMD mem -> xmm */ XMM3P,
/* SIMD xmm -> r32,imm8 */ XMMM,
/* SIMD mem -> xmm */ XMMMS,
/* SIMD xmm -> mem */ XMMSH,
/* SIMD xmm,imm8 */ XMMX3,
/* SIMD xmm -> r32 */ XMMMX,
/* SIMD mm -> xmm */ XMMXM,
/* SIMD xmm -> mm */ XMMSFNC /* SIMD sfence (none or mem) */ #
define FILL 0x90 /* Fill byte used for alignment (nop) */** Register numbers for the i386 * modes for immediate values #
define MODE_IPREL 1 /* signed IP relative value */#
define MODE_IMPLIED 3 /* constant value implied from opcode */#
define MODE_RIPREL 5 /* like IPREL, but from %rip (amd64) */ * The letters used in these macros are: * IND - indirect to another to another table * "T" - means to Terminate indirections (this is the final opcode) * "S" - means "operand length suffix required" * "NS" - means "no suffix" which is the operand length suffix of the opcode * "Z" - means instruction size arg required * "u" - means the opcode is invalid in IA32 but valid in amd64 * "x" - means the opcode is invalid in amd64, but not IA32 * "y" - means the operand size is always 64 bits in 64 bit mode * "p" - means push/pop stack operation #
define TNSZ(
name,
amode,
sz) {
TERM,
amode,
name, 0,
sz, 0, 0, 0, 0}
#
define TNSZy(
name,
amode,
sz) {
TERM,
amode,
name, 0,
sz, 0,
1, 0, 0}
#
define TSZ(
name,
amode,
sz) {
TERM,
amode,
name,
1,
sz, 0, 0, 0, 0}
#
define TSZx(
name,
amode,
sz) {
TERM,
amode,
name,
1,
sz,
1, 0, 0, 0}
#
define TSZy(
name,
amode,
sz) {
TERM,
amode,
name,
1,
sz, 0,
1, 0, 0}
* this decodes the r_m field for mode's 0, 1, 2 in 16 bit mode "(%bx,%si)",
"(%bx,%di)",
"(%bp,%si)",
"(%bp,%di)",
"(%si)",
"(%di)",
"",
"(%bx,%si)",
"(%bx,%di)",
"(%bp,%si)",
"(%bp,%di)",
"(%si)",
"(%di",
"(%bp)",
"(%bx,%si)",
"(%bx,%di)",
"(%bp,%si)",
"(%bp,%di)",
"(%si)",
"(%di)",
"(%bp)",
* This decodes 32 bit addressing mode r_m field for modes 0, 1, 2 "(%eax)",
"(%ecx)",
"(%edx)",
"(%ebx)",
"",
"",
"(%esi)",
"(%edi)",
"(%r8d)",
"(%r9d)",
"(%r10d)",
"(%r11d)",
"",
"",
"(%r14d)",
"(%r15d)" "(%eax)",
"(%ecx)",
"(%edx)",
"(%ebx)",
"",
"(%ebp)",
"(%esi)",
"(%edi)",
"(%r8d)",
"(%r9d)",
"(%r10d)",
"(%r11d)",
"",
"(%r13d)",
"(%r14d)",
"(%r15d)" * This decodes 64 bit addressing mode r_m field for modes 0, 1, 2 "(%rax)",
"(%rcx)",
"(%rdx)",
"(%rbx)",
"",
"(%rip)",
"(%rsi)",
"(%rdi)",
"(%r8)",
"(%r9)",
"(%r10)",
"(%r11)",
"(%r12)",
"(%rip)",
"(%r14)",
"(%r15)" "(%rax)",
"(%rcx)",
"(%rdx)",
"(%rbx)",
"",
"(%rbp)",
"(%rsi)",
"(%rdi)",
"(%r8)",
"(%r9)",
"(%r10)",
"(%r11)",
"(%r12)",
"(%r13)",
"(%r14)",
"(%r15)" * decode for scale from SIB byte * register decoding for normal references to registers (ie. not addressing) "%al",
"%cl",
"%dl",
"%bl",
"%ah",
"%ch",
"%dh",
"%bh",
"%r8b",
"%r9b",
"%r10b",
"%r11b",
"%r12b",
"%r13b",
"%r14b",
"%r15b" "%al",
"%cl",
"%dl",
"%bl",
"%spl",
"%bpl",
"%sil",
"%dil",
"%r8b",
"%r9b",
"%r10b",
"%r11b",
"%r12b",
"%r13b",
"%r14b",
"%r15b" "%ax",
"%cx",
"%dx",
"%bx",
"%sp",
"%bp",
"%si",
"%di",
"%r8w",
"%r9w",
"%r10w",
"%r11w",
"%r12w",
"%r13w",
"%r14w",
"%r15w" "%eax",
"%ecx",
"%edx",
"%ebx",
"%esp",
"%ebp",
"%esi",
"%edi",
"%r8d",
"%r9d",
"%r10d",
"%r11d",
"%r12d",
"%r13d",
"%r14d",
"%r15d" "%rax",
"%rcx",
"%rdx",
"%rbx",
"%rsp",
"%rbp",
"%rsi",
"%rdi",
"%r8",
"%r9",
"%r10",
"%r11",
"%r12",
"%r13",
"%r14",
"%r15" "%db0",
"%db1",
"%db2",
"%db3",
"%db4",
"%db5",
"%db6",
"%db7",
"%db8",
"%db9",
"%db10",
"%db11",
"%db12",
"%db13",
"%db14",
"%db15" "%cr0",
"%cr1",
"%cr2",
"%cr3",
"%cr4",
"%cr5?",
"%cr6?",
"%cr7?",
"%cr8",
"%cr9?",
"%cr10?",
"%cr11?",
"%cr12?",
"%cr13?",
"%cr14?",
"%cr15?" "%tr0?",
"%tr1?",
"%tr2?",
"%tr3",
"%tr4",
"%tr5",
"%tr6",
"%tr7",
"%tr0?",
"%tr1?",
"%tr2?",
"%tr3",
"%tr4",
"%tr5",
"%tr6",
"%tr7" "%mm0",
"%mm1",
"%mm2",
"%mm3",
"%mm4",
"%mm5",
"%mm6",
"%mm7",
"%mm0",
"%mm1",
"%mm2",
"%mm3",
"%mm4",
"%mm5",
"%mm6",
"%mm7" "%xmm0",
"%xmm1",
"%xmm2",
"%xmm3",
"%xmm4",
"%xmm5",
"%xmm6",
"%xmm7",
"%xmm8",
"%xmm9",
"%xmm10",
"%xmm11",
"%xmm12",
"%xmm13",
"%xmm14",
"%xmm15" "%es",
"%cs",
"%ss",
"%ds",
"%fs",
"%gs",
"<reserved>",
"<reserved>",
"%es",
"%cs",
"%ss",
"%ds",
"%fs",
"%gs",
"<reserved>",
"<reserved>" * SIMD predicate suffixes "eq",
"lt",
"le",
"unord",
"neq",
"nlt",
"nle",
"ord" * "decode table" for 64 bit mode MOVSXD instruction (opcode 0x63) * "decode table" for pause and clflush instructions * Decode table for 0x0F00 opcodes * Decode table for 0x0F01 opcodes /* [0] */ TNSZ(
"sgdt",
MO,
6),
TNSZ(
"sidt",
MO,
6),
TNSZ(
"lgdt",
MO,
6),
TNSZ(
"lidt",
MO,
6),
* Decode table for 0x0F18 opcodes -- SIMD prefetch * Decode table for 0x0FAE opcodes -- SIMD state save/restore /* [0] */ TNSZ(
"fxsave",M,
512),
TNSZ(
"fxrstor",M,
512),
TNS(
"ldmxcsr",M),
TNS(
"stmxcsr",M),
* Decode table for 0x0FBA opcodes * Decode table for 0x0FC7 opcode * Decode table for 0x0FC8 opcode -- 486 bswap instruction *bit pattern: 0000 1111 1100 1reg * Decode table for 0x0F71, 0x0F72, and 0x0F73 opcodes -- MMX instructions * Decode table for SIMD extensions to above 0x0F71-0x0F73 opcodes. * SIMD instructions have been wedged into the existing IA32 instruction * set through the use of prefixes. That is, while 0xf0 0x58 may be * addps, 0xf3 0xf0 0x58 (literally, repz addps) is a completely different * instruction - addss. At present, three prefixes have been coopted in * this manner - address size (0x66), repnz (0xf2) and repz (0xf3). The * following tables are used to provide the prefixed instruction names. * The arrays are sparse, but they're fast. * Decode table for SIMD instructions with the address size (0x66) prefix. /* [10] */ TNSZ(
"movupd",
XMM,
16),
TNSZ(
"movupd",
XMMS,
16),
TNSZ(
"movlpd",
XMMM,
8),
TNSZ(
"movlpd",
XMMMS,
8),
/* [14] */ TNSZ(
"unpcklpd",
XMM,
16),
TNSZ(
"unpckhpd",
XMM,
16),
TNSZ(
"movhpd",
XMMM,
8),
TNSZ(
"movhpd",
XMMMS,
8),
/* [28] */ TNSZ(
"movapd",
XMM,
16),
TNSZ(
"movapd",
XMMS,
16),
TNSZ(
"cvtpi2pd",
XMMOMX,
8),
TNSZ(
"movntpd",
XMMOMS,
16),
/* [2C] */ TNSZ(
"cvttpd2pi",
XMMXMM,
16),
TNSZ(
"cvtpd2pi",
XMMXMM,
16),
TNSZ(
"ucomisd",
XMM,
8),
TNSZ(
"comisd",
XMM,
8),
/* [54] */ TNSZ(
"andpd",
XMM,
16),
TNSZ(
"andnpd",
XMM,
16),
TNSZ(
"orpd",
XMM,
16),
TNSZ(
"xorpd",
XMM,
16),
/* [58] */ TNSZ(
"addpd",
XMM,
16),
TNSZ(
"mulpd",
XMM,
16),
TNSZ(
"cvtpd2ps",
XMM,
16),
TNSZ(
"cvtps2dq",
XMM,
16),
/* [5C] */ TNSZ(
"subpd",
XMM,
16),
TNSZ(
"minpd",
XMM,
16),
TNSZ(
"divpd",
XMM,
16),
TNSZ(
"maxpd",
XMM,
16),
/* [60] */ TNSZ(
"punpcklbw",
XMM,
16),
TNSZ(
"punpcklwd",
XMM,
16),
TNSZ(
"punpckldq",
XMM,
16),
TNSZ(
"packsswb",
XMM,
16),
/* [64] */ TNSZ(
"pcmpgtb",
XMM,
16),
TNSZ(
"pcmpgtw",
XMM,
16),
TNSZ(
"pcmpgtd",
XMM,
16),
TNSZ(
"packuswb",
XMM,
16),
/* [68] */ TNSZ(
"punpckhbw",
XMM,
16),
TNSZ(
"punpckhwd",
XMM,
16),
TNSZ(
"punpckhdq",
XMM,
16),
TNSZ(
"packssdw",
XMM,
16),
/* [6C] */ TNSZ(
"punpcklqdq",
XMM,
16),
TNSZ(
"punpckhqdq",
XMM,
16),
TNSZ(
"movd",
XMM3MX,
4),
TNSZ(
"movdqa",
XMM,
16),
/* [74] */ TNSZ(
"pcmpeqb",
XMM,
16),
TNSZ(
"pcmpeqw",
XMM,
16),
TNSZ(
"pcmpeqd",
XMM,
16),
INVALID,
/* [D0] */ INVALID,
TNSZ(
"psrlw",
XMM,
16),
TNSZ(
"psrld",
XMM,
16),
TNSZ(
"psrlq",
XMM,
16),
/* [D4] */ TNSZ(
"paddq",
XMM,
16),
TNSZ(
"pmullw",
XMM,
16),
TNSZ(
"movq",
XMMS,
8),
TNS(
"pmovmskb",
XMMX3),
/* [D8] */ TNSZ(
"psubusb",
XMM,
16),
TNSZ(
"psubusw",
XMM,
16),
TNSZ(
"pminub",
XMM,
16),
TNSZ(
"pand",
XMM,
16),
/* [DC] */ TNSZ(
"paddusb",
XMM,
16),
TNSZ(
"paddusw",
XMM,
16),
TNSZ(
"pmaxub",
XMM,
16),
TNSZ(
"pandn",
XMM,
16),
/* [E0] */ TNSZ(
"pavgb",
XMM,
16),
TNSZ(
"psraw",
XMM,
16),
TNSZ(
"psrad",
XMM,
16),
TNSZ(
"pavgw",
XMM,
16),
/* [E4] */ TNSZ(
"pmulhuw",
XMM,
16),
TNSZ(
"pmulhw",
XMM,
16),
TNSZ(
"cvttpd2dq",
XMM,
16),
TNSZ(
"movntdq",
XMMS,
16),
/* [E8] */ TNSZ(
"psubsb",
XMM,
16),
TNSZ(
"psubsw",
XMM,
16),
TNSZ(
"pminsw",
XMM,
16),
TNSZ(
"por",
XMM,
16),
/* [EC] */ TNSZ(
"paddsb",
XMM,
16),
TNSZ(
"paddsw",
XMM,
16),
TNSZ(
"pmaxsw",
XMM,
16),
TNSZ(
"pxor",
XMM,
16),
/* [F0] */ INVALID,
TNSZ(
"psllw",
XMM,
16),
TNSZ(
"pslld",
XMM,
16),
TNSZ(
"psllq",
XMM,
16),
/* [F4] */ TNSZ(
"pmuludq",
XMM,
16),
TNSZ(
"pmaddwd",
XMM,
16),
TNSZ(
"psadbw",
XMM,
16),
TNSZ(
"maskmovdqu",
XMMXIMPL,
16),
/* [F8] */ TNSZ(
"psubb",
XMM,
16),
TNSZ(
"psubw",
XMM,
16),
TNSZ(
"psubd",
XMM,
16),
TNSZ(
"psubq",
XMM,
16),
/* [FC] */ TNSZ(
"paddb",
XMM,
16),
TNSZ(
"paddw",
XMM,
16),
TNSZ(
"paddd",
XMM,
16),
INVALID,
* Decode table for SIMD instructions with the repnz (0xf2) prefix. /* [58] */ TNSZ(
"addsd",
XMM,
8),
TNSZ(
"mulsd",
XMM,
8),
TNSZ(
"cvtsd2ss",
XMM,
8),
INVALID,
/* [5C] */ TNSZ(
"subsd",
XMM,
8),
TNSZ(
"minsd",
XMM,
8),
TNSZ(
"divsd",
XMM,
8),
TNSZ(
"maxsd",
XMM,
8),
* Decode table for SIMD instructions with the repz (0xf3) prefix. /* [50] */ INVALID,
TNSZ(
"sqrtss",
XMM,
4),
TNSZ(
"rsqrtss",
XMM,
4),
TNSZ(
"rcpss",
XMM,
4),
/* [58] */ TNSZ(
"addss",
XMM,
4),
TNSZ(
"mulss",
XMM,
4),
TNSZ(
"cvtss2sd",
XMM,
4),
TNSZ(
"cvttps2dq",
XMM,
16),
/* [5C] */ TNSZ(
"subss",
XMM,
4),
TNSZ(
"minss",
XMM,
4),
TNSZ(
"divss",
XMM,
4),
TNSZ(
"maxss",
XMM,
4),
* Decode table for 0x0F opcodes /* [10] */ TNSZ(
"movups",
XMMO,
16),
TNSZ(
"movups",
XMMOS,
16),
TNSZ(
"movlps",
XMMO,
8),
TNSZ(
"movlps",
XMMOS,
8),
/* [14] */ TNSZ(
"unpcklps",
XMMO,
16),
TNSZ(
"unpckhps",
XMMO,
16),
TNSZ(
"movhps",
XMMOM,
8),
TNSZ(
"movhps",
XMMOMS,
8),
/* [28] */ TNSZ(
"movaps",
XMMO,
16),
TNSZ(
"movaps",
XMMOS,
16),
TNSZ(
"cvtpi2ps",
XMMOMX,
8),
TNSZ(
"movntps",
XMMOS,
16),
/* [2C] */ TNSZ(
"cvttps2pi",
XMMOXMM,
8),
TNSZ(
"cvtps2pi",
XMMOXMM,
8),
TNSZ(
"ucomiss",
XMMO,
4),
TNSZ(
"comiss",
XMMO,
4),
/* [40] */ TS(
"cmovx.o",
MR),
TS(
"cmovx.no",
MR),
TS(
"cmovx.b",
MR),
TS(
"cmovx.ae",
MR),
/* [44] */ TS(
"cmovx.e",
MR),
TS(
"cmovx.ne",
MR),
TS(
"cmovx.be",
MR),
TS(
"cmovx.a",
MR),
/* [4C] */ TS(
"cmovx.l",
MR),
TS(
"cmovx.ge",
MR),
TS(
"cmovx.le",
MR),
TS(
"cmovx.g",
MR),
/* [50] */ TNS(
"movmskps",
XMMOX3),
TNSZ(
"sqrtps",
XMMO,
16),
TNSZ(
"rsqrtps",
XMMO,
16),
TNSZ(
"rcpps",
XMMO,
16),
/* [54] */ TNSZ(
"andps",
XMMO,
16),
TNSZ(
"andnps",
XMMO,
16),
TNSZ(
"orps",
XMMO,
16),
TNSZ(
"xorps",
XMMO,
16),
/* [58] */ TNSZ(
"addps",
XMMO,
16),
TNSZ(
"mulps",
XMMO,
16),
TNSZ(
"cvtps2pd",
XMMO,
8),
TNSZ(
"cvtdq2ps",
XMMO,
16),
/* [5C] */ TNSZ(
"subps",
XMMO,
16),
TNSZ(
"minps",
XMMO,
16),
TNSZ(
"divps",
XMMO,
16),
TNSZ(
"maxps",
XMMO,
16),
/* [60] */ TNSZ(
"punpcklbw",
MMO,
4),
TNSZ(
"punpcklwd",
MMO,
4),
TNSZ(
"punpckldq",
MMO,
4),
TNSZ(
"packsswb",
MMO,
8),
/* [64] */ TNSZ(
"pcmpgtb",
MMO,
8),
TNSZ(
"pcmpgtw",
MMO,
8),
TNSZ(
"pcmpgtd",
MMO,
8),
TNSZ(
"packuswb",
MMO,
8),
/* [68] */ TNSZ(
"punpckhbw",
MMO,
8),
TNSZ(
"punpckhwd",
MMO,
8),
TNSZ(
"punpckhdq",
MMO,
8),
TNSZ(
"packssdw",
MMO,
8),
/* [6C] */ TNSZ(
"INVALID",
MMO,0),
TNSZ(
"INVALID",
MMO,0),
TNSZ(
"movd",
MMO,
4),
TNSZ(
"movq",
MMO,
8),
/* [74] */ TNSZ(
"pcmpeqb",
MMO,
8),
TNSZ(
"pcmpeqw",
MMO,
8),
TNSZ(
"pcmpeqd",
MMO,
8),
TNS(
"emms",
NORM),
/* [80] */ TNS(
"jo",D),
TNS(
"jno",D),
TNS(
"jb",D),
TNS(
"jae",D),
/* [84] */ TNS(
"je",D),
TNS(
"jne",D),
TNS(
"jbe",D),
TNS(
"ja",D),
/* [88] */ TNS(
"js",D),
TNS(
"jns",D),
TNS(
"jp",D),
TNS(
"jnp",D),
/* [8C] */ TNS(
"jl",D),
TNS(
"jge",D),
TNS(
"jle",D),
TNS(
"jg",D),
/* [D0] */ INVALID,
TNSZ(
"psrlw",
MMO,
8),
TNSZ(
"psrld",
MMO,
8),
TNSZ(
"psrlq",
MMO,
8),
/* [D4] */ TNSZ(
"paddq",
MMO,
8),
TNSZ(
"pmullw",
MMO,
8),
TNSZ(
"INVALID",
MMO,0),
TNS(
"pmovmskb",
MMOM3),
/* [D8] */ TNSZ(
"psubusb",
MMO,
8),
TNSZ(
"psubusw",
MMO,
8),
TNSZ(
"pminub",
MMO,
8),
TNSZ(
"pand",
MMO,
8),
/* [DC] */ TNSZ(
"paddusb",
MMO,
8),
TNSZ(
"paddusw",
MMO,
8),
TNSZ(
"pmaxub",
MMO,
8),
TNSZ(
"pandn",
MMO,
8),
/* [E0] */ TNSZ(
"pavgb",
MMO,
8),
TNSZ(
"psraw",
MMO,
8),
TNSZ(
"psrad",
MMO,
8),
TNSZ(
"pavgw",
MMO,
8),
/* [E4] */ TNSZ(
"pmulhuw",
MMO,
8),
TNSZ(
"pmulhw",
MMO,
8),
TNS(
"INVALID",
XMMO),
TNSZ(
"movntq",
MMOMS,
8),
/* [E8] */ TNSZ(
"psubsb",
MMO,
8),
TNSZ(
"psubsw",
MMO,
8),
TNSZ(
"pminsw",
MMO,
8),
TNSZ(
"por",
MMO,
8),
/* [EC] */ TNSZ(
"paddsb",
MMO,
8),
TNSZ(
"paddsw",
MMO,
8),
TNSZ(
"pmaxsw",
MMO,
8),
TNSZ(
"pxor",
MMO,
8),
/* [F0] */ INVALID,
TNSZ(
"psllw",
MMO,
8),
TNSZ(
"pslld",
MMO,
8),
TNSZ(
"psllq",
MMO,
8),
/* [F4] */ TNSZ(
"pmuludq",
MMO,
8),
TNSZ(
"pmaddwd",
MMO,
8),
TNSZ(
"psadbw",
MMO,
8),
TNSZ(
"maskmovq",
MMOIMPL,
8),
/* [F8] */ TNSZ(
"psubb",
MMO,
8),
TNSZ(
"psubw",
MMO,
8),
TNSZ(
"psubd",
MMO,
8),
TNSZ(
"psubq",
MMO,
8),
/* [FC] */ TNSZ(
"paddb",
MMO,
8),
TNSZ(
"paddw",
MMO,
8),
TNSZ(
"paddd",
MMO,
8),
INVALID,
* Decode table for 0x80 opcodes * Decode table for 0x81 opcodes. * Decode table for 0x82 opcodes. * Decode table for 0x83 opcodes. * Decode table for 0xC0 opcodes. * Decode table for 0xD0 opcodes. * Decode table for 0xC1 opcodes. * Decode table for 0xD1 opcodes. * Decode table for 0xD2 opcodes. * Decode table for 0xD3 opcodes. * Decode table for 0xF6 opcodes. * Decode table for 0xF7 opcodes. * Decode table for 0xFE opcodes. * Decode table for 0xFF opcodes. /* for 287 instructions, which are a mess to decode */ /* bit pattern: 1101 1xxx MODxx xR/M */ /* [0,0] */ TNS(
"fadds",M),
TNS(
"fmuls",M),
TNS(
"fcoms",M),
TNS(
"fcomps",M),
/* [0,4] */ TNS(
"fsubs",M),
TNS(
"fsubrs",M),
TNS(
"fdivs",M),
TNS(
"fdivrs",M),
/* [1,4] */ TNSZ(
"fldenv",M,
28),
TNSZ(
"fldcw",M,
2),
TNSZ(
"fnstenv",M,
28),
TNSZ(
"fnstcw",M,
2),
/* [2,0] */ TNS(
"fiaddl",M),
TNS(
"fimull",M),
TNS(
"ficoml",M),
TNS(
"ficompl",M),
/* [2,4] */ TNS(
"fisubl",M),
TNS(
"fisubrl",M),
TNS(
"fidivl",M),
TNS(
"fidivrl",M),
/* [4,0] */ TNSZ(
"faddl",M,
8),
TNSZ(
"fmull",M,
8),
TNSZ(
"fcoml",M,
8),
TNSZ(
"fcompl",M,
8),
/* [4,1] */ TNSZ(
"fsubl",M,
8),
TNSZ(
"fsubrl",M,
8),
TNSZ(
"fdivl",M,
8),
TNSZ(
"fdivrl",M,
8),
/* [5,0] */ TNSZ(
"fldl",M,
8),
INVALID,
TNSZ(
"fstl",M,
8),
TNSZ(
"fstpl",M,
8),
/* [5,4] */ TNSZ(
"frstor",M,
108),
INVALID,
TNSZ(
"fnsave",M,
108),
TNSZ(
"fnstsw",M,
2),
/* [6,0] */ TNSZ(
"fiadd",M,
2),
TNSZ(
"fimul",M,
2),
TNSZ(
"ficom",M,
2),
TNSZ(
"ficomp",M,
2),
/* [6,4] */ TNSZ(
"fisub",M,
2),
TNSZ(
"fisubr",M,
2),
TNSZ(
"fidiv",M,
2),
TNSZ(
"fidivr",M,
2),
/* [7,0] */ TNSZ(
"fild",M,
2),
INVALID,
TNSZ(
"fist",M,
2),
TNSZ(
"fistp",M,
2),
/* [7,4] */ TNSZ(
"fbld",M,
10),
TNSZ(
"fildll",M,
8),
TNSZ(
"fbstp",M,
10),
TNSZ(
"fistpll",M,
8),
/* bit pattern: 1101 1xxx 11xx xREG */ /* [5,0] */ TNS(
"ffree",F),
TNS(
"fxch",F),
TNS(
"fst",F),
TNS(
"fstp",F),
/* [7,0] */ TNS(
"ffreep",F),
TNS(
"fxch",F),
TNS(
"fstp",F),
TNS(
"fstp",F),
/* bit pattern: 1101 1001 111x xxxx */ /* bit pattern: 1101 1011 111x xxxx */ /* bit pattern: 1101 1011 11yy yxxx */ /* bit pattern: 1101 1010 11yy yxxx */ * Main decode table for the op codes. The first two nibbles * will be used as an index into the table. If there is a * a need to further decode an instruction, the array to be * referenced is indicated with the other two entries being /* [4,0] */ TSx(
"inc",R),
TSx(
"inc",R),
TSx(
"inc",R),
TSx(
"inc",R),
/* [4,4] */ TSx(
"inc",R),
TSx(
"inc",R),
TSx(
"inc",R),
TSx(
"inc",R),
/* [4,8] */ TSx(
"dec",R),
TSx(
"dec",R),
TSx(
"dec",R),
TSx(
"dec",R),
/* [4,C] */ TSx(
"dec",R),
TSx(
"dec",R),
TSx(
"dec",R),
TSx(
"dec",R),
/* [5,0] */ TSp(
"push",R),
TSp(
"push",R),
TSp(
"push",R),
TSp(
"push",R),
/* [5,4] */ TSp(
"push",R),
TSp(
"push",R),
TSp(
"push",R),
TSp(
"push",R),
/* [5,8] */ TSp(
"pop",R),
TSp(
"pop",R),
TSp(
"pop",R),
TSp(
"pop",R),
/* [5,C] */ TSp(
"pop",R),
TSp(
"pop",R),
TSp(
"pop",R),
TSp(
"pop",R),
/* [6,0] */ TSZx(
"pusha",
IMPLMEM,
28),
TSZx(
"popa",
IMPLMEM,
28),
TSx(
"bound",
MR),
TNS(
"arpl",
RMw),
/* [6,C] */ TNSZ(
"insb",
IMPLMEM,
1),
TSZ(
"ins",
IMPLMEM,
4),
TNSZ(
"outsb",
IMPLMEM,
1),
TSZ(
"outs",
IMPLMEM,
4),
/* [9,C] */ TSZy(
"pushf",
IMPLMEM,
4),
TSZy(
"popf",
IMPLMEM,
4),
TNSx(
"sahf",
NORM),
TNSx(
"lahf",
NORM),
/* [A,4] */ TNSZ(
"movsb",
SD,
1),
TS(
"movs",
SD),
TNSZ(
"cmpsb",
SD,
1),
TS(
"cmps",
SD),
/* [D,4] */ TNSx(
"aam",U),
TNSx(
"aad",U),
TNSx(
"falc",
NORM),
TNSZ(
"xlat",
IMPLMEM,
1),
/* 287 instructions. Note that although the indirect field */ /* indicates opFP1n2 for further decoding, this is not necessarily */ /* the case since the opFP arrays are not partitioned according to key1 */ /* and key2. opFP1n2 is given only to indicate that we haven't */ /* finished decoding the instruction. */ /* [E,4] */ TNS(
"inb",P),
TS(
"in",P),
TNS(
"outb",P),
TS(
"out",P),
/* [E,C] */ TNS(
"inb",V),
TS(
"in",V),
TNS(
"outb",V),
TS(
"out",V),
* common functions to decode and disassemble an x86 or amd64 instruction * These are the individual fields of a REX prefix. Note that a REX * prefix with none of these set is still needed to: * - use the MOVSXD (sign extend 32 to 64 bits) instruction * - access the %sil, %dil, %bpl, %spl registers #
define REX_W 0x08 /* 64 bit operand size when set */#
define REX_R 0x04 /* high order bit extension of ModRM reg field */#
define REX_X 0x02 /* high order bit extension of SIB index field */#
define REX_B 0x01 /* extends ModRM r_m, SIB base, or opcode reg */ * Even in 64 bit mode, usually only 4 byte immediate operands are supported. static int isize[] = {
1,
2,
4,
4};
static int isize64[] = {
1,
2,
4,
8};
* Just a bunch of useful macros. #
define WBIT(x) (x &
0x1)
/* to get w bit */#
define REGNO(x) (x &
0x7)
/* to get 3 bit register */#
define VBIT(x) ((x)>>
1 &
0x1)
/* to get 'v' bit */#
define REG_ONLY 3 /* mode to indicate a register operand (not memory) */#
define BYTE_OPND 0
/* w-bit value indicating byte register */#
define LONG_OPND 1 /* w-bit value indicating opnd_size register */#
define MM_OPND 2 /* "value" used to indicate a mmx reg */#
define XMM_OPND 3 /* "value" used to indicate a xmm reg */#
define SEG_OPND 4 /* "value" used to indicate a segment reg */#
define CONTROL_OPND 5 /* "value" used to indicate a control reg */#
define DEBUG_OPND 6 /* "value" used to indicate a debug reg */#
define TEST_OPND 7 /* "value" used to indicate a test reg */#
define WORD_OPND 8 /* w-bit value indicating word size reg */ * Get the next byte and separate the op code into the high and low nibbles. * x86 instructions have a maximum length of 15 bytes. Bail out if *
low =
byte &
0xf;
/* ----xxxx low 4 bits */ *
high =
byte >>
4 &
0xf;
/* xxxx---- bits 7 to 4 */ * Get and decode an SIB (scaled index base) byte * Get the byte following the op code and separate it into the * mode, register, and r/m fields. * Adjust register selection based on any REX prefix bits present. * Get an immediate operand of the given size, with sign extension. for (i = 0; i <
size; ++i) {
* Get an ip relative operand of the given size, with sign extension. * Check to see if there is a segment override prefix pending. * If so, print it in the current 'operand' location and set * the override flag back to false. * Process a single instruction Register or Memory operand. * mode = addressing mode from ModRM byte * r_m = r_m (or reg if mode == 3) field from ModRM byte * wbit = indicates which register (8bit, 16bit, ... MMX, etc.) set to use. * o = index of operand that we are processing (0, 1 or 2) * the value of reg or r_m must have already been adjusted for any REX prefix. int have_SIB = 0;
/* flag presence of scale-index-byte */ uint_t ss;
/* scale-factor from opcode */ int dispsize;
/* size of displacement in bytes */ * first handle a simple register * if symbolic representation, skip override prefix, if any * Handle 16 bit memory references first, since they decode * the mode values more simply. * mode 1 is r_m + 8 bit displacement * mode 2 is r_m + 16 bit displacement * mode 0 is just r_m, unless r_m is 6 which is 16 bit disp * 32 and 64 bit addressing modes are more complex since they * can involve an SIB (scaled index and base) byte to decode. * Compute the displacement size and get its bytes * print the base (if any) * print the index (if any) * Operand sequence for standard instruction involving one register * wbit indicates a byte(0) or opnd_size(1) operation * vbit indicates direction (0 for "opcode r,r_m") or (1 for "opcode r_m, r") * Similar to above, but allows for the two operands to be of different * wbit is for the r_m operand * w2 is for the reg operand * Similar, but for 2 operands plus an immediate. * Dissassemble a single x86 or amd64 instruction. * Mode determines the default operating mode (SIZE16, SIZE32 or SIZE64) * for interpreting instructions. * returns non-zero for bad opcode #
define NOMEM /* nothing */ uint_t wbit;
/* opcode wbit, 0 is 8 bit, !0 for opnd_size */ uint_t w2;
/* wbit value for second operand */ * legacy prefixes come in 5 flavors, you should have only one of each for (i = 0; i <
3; ++i) {
* Get one opcode byte and check for zero padding that follows * Gather up legacy x86 prefix bytes. * Handle amd64 mode PREFIX values. * Some of the segment prefixes are no-ops. (only FS/GS actually work) * We might have a REX prefix (opcodes 0x40-0x4f) * Deal with selection of operand and address size now. * Note that the REX.W bit being set causes opnd_size_prefix to be * The pause instruction - a repz'd nop. This doesn't fit * with any of the other prefix goop added for SSE, so we'll * Some 386 instructions have 2 bytes of opcode before the mod_r/m * byte so we may need to perform a table indirection. * If still not at a TERM decode entry, then a ModRM byte * exists and its fields further decode the instruction. * decode 287 instructions (D8-DF) from opcodeN * In amd64 bit mode, ARPL opcode is changed to MOVSXD * (sign extend 32bit to 64 bit) * at this point we should have a correct (or invalid) opcode * deal with MMX/SSE opcodes which are changed by prefixes * This is horrible. Some SIMD instructions take the * form 0x0F 0x?? ..., which is easily decoded using the * existing tables. Other SIMD instructions use various * prefix bytes to overload existing instructions. For * Example, addps is F0, 58, whereas addss is F3 (repz), * F0, 58. Presumably someone got a raise for this. * If we see one of the instructions which can be * modified in this way (if we've got one of the SIMDO* * address modes), we'll check to see if the last prefix * was a repz. If it was, we strip the prefix from the * mnemonic, and we indirect using the dis_opSIMDrepz * Calculate our offset in dis_op0F * Rewrite if this instruction used one of the magic prefixes. * As with the "normal" SIMD instructions, the MMX * shuffle instructions are overloaded. These * instructions, however, are special in that they use * an extra byte, and thus an extra table. As of this * writing, they only use the opnd_size prefix. * Calculate our offset in dis_op0F7123 * In 64 bit mode, some opcodes automatically use opnd_size == SIZE64. * At this point most instructions can format the opcode mnemonic * including the prefixes. char *
types[] = {
"",
"w",
"l",
"q"};
/* It's a cmovx.yy. Replace the suffix x */ for (i =
5; i <
OPLEN; i++) {
* Process operands based on the addressing modes. * amd64 instruction to sign extend 32 bit reg/mem operands * into 64 bit register values * movsbl movsbw movsbq (0x0FBE) or movswl movswq (0x0FBF) * movzbl movzbw movzbq (0x0FB6) or movzwl movzwq (0x0FB7) * wbit lives in 2nd byte, note that operands /* target register size = 64 bit */ * imul instruction, with either 8-bit or longer immediate * opcode 0x6B for byte, sign-extended displacement, 0x69 for word(s) /* memory or register operand to register, with 'w' bit */ /* register to memory or register operand, with 'w' bit */ /* arpl happens to fit here also because it is odd */ /* MMX register to memory or register operand */ /* MMX register to memory */ /* Double shift. Has immediate operand specifying the shift. */ * Double shift. With no immediate operand, specifies using %cl. /* immediate to memory or register operand */ * Have long immediate for opcode 0x81, but not 0x80 nor 0x83 /* immediate to memory or register operand with the */ /* immediate to register with register in low 3 bits */ /* w-bit here (with regs) is bit 3 */ /* MMX immediate shift of register */ /* SIMD immediate shift of register */ /* accumulator to memory operand */ /* memory operand to accumulator */ /* segment register to memory or register operand */ /* memory or register operand to segment register */ * rotate or shift instructions, which may shift by 1 or * consult the cl register, depending on the 'v' bit * immediate rotate or shift instructions /* bit test instructions */ /* single memory or register operand with 'w' bit present */ /* prefetch instruction - memory operand, but no memory acess */ /* single memory or register operand */ /* single memory or register byte operand */ /* Similar to M, but only memory (no direct registers) */ /* move special register to register or reverse if vbit */ * single register operand with register in the low 3 * register to accumulator with register in the low 3 * bits of op code, xchg instructions * single segment register operand, with register in * bits 3-4 of op code byte * single segment register operand, with register in /* long seg reg from opcode */ /* memory or register operand to register */ mode = 0;
/* change for memory access size... */ /* MMX/SIMD-Int and SIMD-FP predicated mm reg to r32 */ /* SIMD memory or xmm reg operand to xmm reg */ * movlps and movhlps share opcodes. They differ in the * addressing modes allowed for their operands. * movhps and movlhps behave similarly. mode = 0;
/* change for memory access size... */ /* SIMD xmm reg to memory or xmm reg */ /* SIMD memory to xmm reg */ /* SIMD memory or r32 to xmm reg */ /* SIMD memory or mm reg to xmm reg */ /* SIMD memory or xmm reg to mm reg */ /* SIMD memory or xmm reg to r32 */ /* SIMD predicated memory or xmm reg with/to xmm reg */ * cmpps and cmpss vary their instruction name based * on the value of imm8. Other XMMP instructions, * such as shufps, require explicit specification of /* immediate operand to accumulator */ /* memory or register operand to accumulator */ /* si register to di register used to reference memory */ /* accumulator to di register */ /* si register to accumulator */ * single operand, a 16/32 bit displacement /* jmp/call indirect to memory or register operand */ * for long jumps and long calls -- a new code segment * register and an offset in IP -- stored in object * code in reverse order. Note - not valid in amd64 /* will now get segment operand */ * jmp/call. single operand, 8 bit displacement. * added to current EIP in 'compofff' /* single 32/16 bit immediate operand */ /* single 8 bit immediate operand */ /* 16-bit immediate operand */ /* single 8 bit port operand */ /* single operand, dx register (variable port instruction) */ * The int instruction, which has two forms: * int n, where n is indicated in the subsequent * byte (format Ib). The int 3 instruction (opcode 0xCC), * where, although the 3 looks like an operand, * it is implied by the opcode. It must be converted * to the correct base and output. /* single 8 bit immediate operand */ /* an unused byte must be discarded */ * sfence is sfence if mode is REG_ONLY. If mode isn't * REG_ONLY, mnemonic should be 'clflush'. /* sfence doesn't take operands */ * no disassembly, the mnemonic was all there was so go on * Only the following exact byte sequences are allowed: /* float reg to float reg, with ret bit present */ case FFC:
/* case for vbit always = 0 */ * compute the size of any memory accessed by the instruction * In 64 bit mode descriptor table entries * go up to 10 bytes and popf/pushf are always 8 bytes * Some instructions should have immediate operands printed * as unsigned integers. We compare against this table. "or",
"and",
"xor",
"test",
"in",
"out",
"lcall",
"ljmp",
"rcr",
"rcl",
"ror",
"rol",
"shl",
"shr",
"sal",
"psr",
"psl",
* Work back to start of last mnemonic, since we may have * prefixes on some opcodes. * Print a numeric immediate into end of buf, maximum length buflen. * The immediate may be an address or a displacement. Mask is set * for address size. If the immediate is a "small negative", or * if it's a negative displacement of any magnitude, print as -<absval>. * Respect the "octal" flag. "Small negative" is defined as "in the * interval [NEG_LIMIT, 0)". * Also, "isunsigned_op()" instructions never print negatives. * Return whether we decided to print a negative value or not. {
0xffU,
0xffffU,
0xffffffffU,
0xffffffffffffffffULL};
* For PC-relative jumps, the pc is really the next pc after executing * this instruction, so increment it appropriately. * sv is for the signed, possibly-truncated immediate or * displacement; usv retains the original size and * unsignedness for symbol lookup. * About masks: for immediates that represent * addresses, the appropriate display size is * the effective address size of the instruction. * This includes MODE_OFFSET, MODE_IPREL, and * MODE_RIPREL. Immediates that are simply * immediate values should display in the operand's * size, however, since they don't represent addresses. /* d86_addr_size is SIZEnn, which is log2(real size) */ /* d86_value_size and d86_imm_bytes are in bytes */ * We printed a negative value for an * immediate that wasn't a * displacement. Note that fact so we can * print the positive value as an * The symbol lookups may result in false positives, * particularly on object files, where small numbers may match * the 0-relative non-relocated addresses of symbols. * If we printed a negative immediate above, print the * positive in case our heuristic was unhelpful /* Print symbol or effective address for reltgt */