#include "tok.h" #include "table.h" #include #define _DISASM_ /* Percent tokens in strings: First char after '%': A - direct address C - reg of r/m picks control register D - reg of r/m picks debug register E - r/m picks operand F - second operand for mmx instruction reg/mem G - reg of r/m picks general register I - immediate data J - relative IP offset + K - call/jmp distance L - first operand for mmx instruction M - r/m picks memory O - no r/m, offset only R - mod of r/m picks register only S - reg of r/m picks segment register T - reg of r/m picks test register X - DS:ESI Y - ES:EDI 2 - prefix of two-byte opcode + e - put in 'e' if use32 (second char is part of reg name) + put in 'w' for use16 or 'd' for use32 (second char is 'w') + j - put in 'e' in jcxz if prefix==0x66 f - floating point (second char is esc value) g - do r/m group 'n', n==0..7 p - prefix s - size override (second char is a,o) + d - put d if double arg, nothing otherwise (pushfd, popfd &c) + w - put w if word, d if double arg, nothing otherwise (lodsw/lodsd) + P - simple prefix Second char after '%': a - two words in memory (BOUND) b - byte c - byte or word d - dword + f - far call/jmp + n - near call/jmp p - 32 or 48 bit pointer + q - byte/word thingy s - six byte pseudo-descriptor v - word or dword w - word + x - sign extended byte y - qword F - use floating regs in mod/rm M - use MMX regs 1-8 - group number, esc value, etc m - no size memory operand */ /* watch out for aad && aam with odd operands */ char *opmap1[256]={ /* 0 */ "add %Eb,%Rb", "add %Ev,%Rv", "add %Rb,%Eb", "add %Rv,%Ev", "add al,%Ib", "add %eax,%Iv", "push es", "pop es", "or %Eb,%Rb", "or %Ev,%Rv", "or %Rb,%Eb", "or %Rv,%Ev", "or al,%Ib", "or %eax,%Iv", "push cs", "%2 ", /* 1 */ "adc %Eb,%Rb", "adc %Ev,%Rv", "adc %Rb,%Eb", "adc %Rv,%Ev", "adc al,%Ib", "adc %eax,%Iv", "push ss", "pop ss", "sbb %Eb,%Rb", "sbb %Ev,%Rv", "sbb %Rb,%Eb", "sbb %Rv,%Ev", "sbb al,%Ib", "sbb %eax,%Iv", "push ds", "pop ds", /* 2 */ "and %Eb,%Rb", "and %Ev,%Rv", "and %Rb,%Eb", "and %Rv,%Ev", "and al,%Ib", "and %eax,%Iv", "%pe", "daa", "sub %Eb,%Rb", "sub %Ev,%Rv", "sub %Rb,%Eb", "sub %Rv,%Ev", "sub al,%Ib", "sub %eax,%Iv", "%pc", "das", /* 3 */ "xor %Eb,%Rb", "xor %Ev,%Rv", "xor %Rb,%Eb", "xor %Rv,%Ev", "xor al,%Ib", "xor %eax,%Iv", "%ps", "aaa", "cmp %Eb,%Rb", "cmp %Ev,%Rv", "cmp %Rb,%Eb", "cmp %Rv,%Ev", "cmp al,%Ib", "cmp %eax,%Iv", "%pd", "aas", /* 4 */ "inc %eax", "inc %ecx", "inc %edx", "inc %ebx", "inc %esp", "inc %ebp", "inc %esi", "inc %edi", "dec %eax", "dec %ecx", "dec %edx", "dec %ebx", "dec %esp", "dec %ebp", "dec %esi", "dec %edi", /* 5 */ "push %eax", "push %ecx", "push %edx", "push %ebx", "push %esp", "push %ebp", "push %esi", "push %edi", "pop %eax", "pop %ecx", "pop %edx", "pop %ebx", "pop %esp", "pop %ebp", "pop %esi", "pop %edi", /* 6 */ "pusha%d ", "popa%d ", "bound %Rv,%Ma", "arpl %Ew,%Rw", "%pf", "%pg", "%so", "%sa", "push %Iv", "imul %Rv,%Ev,%Iv","push %Ix", "imul %Rv,%Ev,%Ib", "insb", "ins%ew", "outsb", "outs%ew", /* 7 */ "jo %Jb", "jno %Jb", "jc %Jb", "jnc %Jb", "je %Jb", "jne %Jb", "jbe %Jb", "ja %Jb", "js %Jb", "jns %Jb", "jpe %Jb", "jpo %Jb", "jl %Jb", "jge %Jb", "jle %Jb", "jg %Jb", /* 8 */ /* "%g0 %Eb,%Ib", "%g0 %Ev,%Iv", "%g0 %Ev,%Ib", "%g0 %Ev,%Ib", */ "%g0 %Eb,%Ib", "%g0 %Ev,%Iv", "%g0 %Ev,%Ix", "%g0 %Ev,%Ix", "test %Eb,%Rb", "test %Ev,%Rv", "xchg %Eb,%Rb", "xchg %Ev,%Rv", "mov %Eb,%Rb", "mov %Ev,%Rv", "mov %Rb,%Eb", "mov %Rv,%Ev", "mov %Ew,%Sw", "lea %Rv,%M ", "mov %Sw,%Ew", "pop %Ev", /* 9 */ "nop", "xchg %ecx,%eax", "xchg %edx,%eax", "xchg %ebx,%eax", "xchg %esp,%eax", "xchg %ebp,%eax", "xchg %esi,%eax", "xchg %edi,%eax", "cbw", "cwd", "call %Ap", "fwait", "pushf%d ", "popf%d ", "sahf", "lahf", /* a */ "mov al,%Oc", "mov %eax,%Ov", "mov %Oc,al", "mov %Ov,%eax", "%P movsb", "%P movs%w", "%P cmpsb", "%P cmps%w ", "test al,%Ib", "test %eax,%Iv", "%P stosb", "%P stos%w ", "%P lodsb", "%P lods%w ", "%P scasb", "%P scas%w ", /* b */ "mov al,%Ib", "mov cl,%Ib", "mov dl,%Ib", "mov bl,%Ib", "mov ah,%Ib", "mov ch,%Ib", "mov dh,%Ib", "mov bh,%Ib", "mov %eax,%Iv", "mov %ecx,%Iv", "mov %edx,%Iv", "mov %ebx,%Iv", "mov %esp,%Iv", "mov %ebp,%Iv", "mov %esi,%Iv", "mov %edi,%Iv", /* c */ "%g1 %Eb,%Ib", "%g1 %Ev,%Ib", "ret %Iw", "ret", "les %Rv,%Mp", "lds %Rv,%Mp", "mov %Eb,%Ib", "mov %Ev,%Iv", "enter %Iw,%Ib", "leave", "retf %Iw", "retf", "int 03", "int %Ib", "into", "iret", /* d */ "%g1 %Eb,1", "%g1 %Ev,1", "%g1 %Eb,cl", "%g1 %Ev,cl", "aam ; %Ib", "aad ; %Ib", "setalc", "xlat", /*#if 0 "esc 0,%Ib", "esc 1,%Ib", "esc 2,%Ib", "esc 3,%Ib", "esc 4,%Ib", "esc 5,%Ib", "esc 6,%Ib", "esc 7,%Ib", #else */ "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", //#endif /* e */ "loopne %Jb", "loope %Jb", "loop %Jb", "j%j cxz %Jb", "in al,%Ib", "in %eax,%Ib", "out %Ib,al", "out %Ib,%eax", "call %Jv", "jmp %Jv", "jmp %Ap", "jmp %Ks%Jb", "in al,dx", "in %eax,dx", "out dx,al", "out dx,%eax", /* f */ "lock %p ", 0, "repne %p ", "repe %p ", "hlt", "cmc", "%g2", "%g2", "clc", "stc", "cli", "sti", "cld", "std", "%g3", "%g4" }; char *second[] = { /* 0 */ "%g5", "%g6", "lar %Rv,%Ew", "lsl %Rv,%Ew", 0, "loadall", "clts", "loadall", "invd", "wbinvd", 0, "ud2", 0, 0, 0, 0, /* 1 */ "movups %RX,%EX", "movups %Md,%RX", "%x0", "movlps %Md,%RX", "unpcklps %RX,%EX", "unpckhps %RX,%EX","%x1", "movhps %Md,%RX", "%g7", 0, 0, 0, 0, 0, 0, 0, /* 2 */ "mov %Ed,%Cd", "mov %Ed,%Dd", "mov %Cd,%Ed", "mov %Dd,%Ed", "mov %Ed,%Td", 0, "mov %Td,%Ed", 0, "movaps %RX,%EX", "movaps %Md,%RX", "cvtpi2ps %RX,%EM","movntps %Md,%RX", "cvttps2pi %RM,%EX","cvtps2pi %RM,%EX","ucomiss %RX,%EX", "comiss %RX,%EX", /* 3 */ "wrmsr", "rdtsc", "rdmsr", "rdpmc", "sysenter", "sysexit", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ "cmovo %Rv,%Ev", "cmovno %Rv,%Ev", "cmovc %Rv,%Ev", "cmovnc %Rv,%Ev", "cmovz %Rv,%Ev", "cmovnz %Rv,%Ev", "cmovbe %Rv,%Ev", "cmovnbe %Rv,%Ev", "cmovs %Rv,%Ev", "cmovns %Rv,%Ev", "cmovp %Rv,%Ev", "cmovnp %Rv,%Ev", "cmovl %Rv,%Ev", "cmovge %Rv,%Ev", "cmovle %Rv,%Ev", "cmovg %Rv,%Ev", /* 5 */ "movmskps %Rd,%GX", "sqrtps %RX,%EX", "rsqrtps %RX,%EX", "rcpps %RX,%EX", "andps %RX,%EX", "andnps %RX,%EX", "orps %RX,%EX", "xorps %RX,%EX", "addps %RX,%EX", "mulps %RX,%EX", "cvtps2pd %RX,%EX","cvtdq2ps %RX,%EX", "subps %RX,%EX", "minps %RX,%EX", "divps %RX,%EX", "maxps %RX,%EX", /* 6 */ "punpcklbw %RM,%EM", "punpcklwd %RM,%EM", "punpckldq %RM,%EM", "packsswb %RM,%EM", "pcmpgtb %RM,%EM", "pcmpgtw %RM,%EM", "pcmpgtd %RM,%EM", "packuswb %RM,%EM", "punpckhbw %RM,%EM", "punpckhwd %RM,%EM", "punpckhdq %RM,%EM", "packssdw %RM,%EM", 0, 0, "movd %RM,%Md", "movq %RM,%EM", /* 7 */ "pshufw %LM,%FM,%Ib","%g3w %EM,%Ib", "%g3d %EM,%Ib", "%g3q %EM,%Ib", "pcmpeqb %RM,%EM", "pcmpeqw %RM,%EM", "pcmpeqd %RM,%EM", "emms", 0, 0, 0, 0, 0, 0, "movd %Md,%RM", "movq %Md,%RM", /* 8 */ "jo %Jv", "jno %Jv", "jb %Jv", "jnb %Jv", "jz %Jv", "jnz %Jv", "jbe %Jv", "ja %Jv", "js %Jv", "jns %Jv", "jp %Jv", "jnp %Jv", "jl %Jv", "jge %Jv", "jle %Jv", "jg %Jv", /* 9 */ "seto %Eb", "setno %Eb", "setc %Eb", "setnc %Eb", "setz %Eb", "setnz %Eb", "setbe %Eb", "setnbe %Eb", "sets %Eb", "setns %Eb", "setp %Eb", "setnp %Eb", "setl %Eb", "setge %Eb", "setle %Eb", "setg %Eb", /* a */ "push fs", "pop fs", "cpuid", "bt %Ev,%Rv", "shld %Ev,%Rv,%Ib", "shld %Ev,%Rv,cl", 0, 0, "push gs", "pop gs", "rsm", "bts %Ev,%Rv", "shrd %Ev,%Rv,%Ib", "shrd %Ev,%Rv,cl", "%g8", "imul %Rv,%Ev", /* b */ "cmpxchg %Eb,%Rb", "cmpxchg %Ev,%Rv", "lss %Rv,%Mp", "btr %Ev,%Rv", "lfs %Rv,%Mp", "lgs %Rv,%Mp", "movzx %Rv,%Eb", "movzx %Rv,%Ew", 0, 0, "%g7 %Ev,%Ib", "btc %Ev,%Rv", "bsf %Rv,%Ev", "bsr %Rv,%Ev", "movsx %Rv,%Eb", "movsx %Rv,%Ew", /* c */ "xadd %Eb,%Rb", "xadd %Ev,%Rv", "cmpps %RX,%EX,%Ib","movnti %Md,%Rd", "pinsrw %LM,%Fd,%Ib","pextrw %Gd,%RM,%Ib","shufps %RX,%EX,%Ib","cmpxchg8b %Myv", "bswap eax", "bswap ecx", "bswap edx", "bswap ebx", "bswap esp", "bswap ebp", "bswap esi", "bswap edi", /* d */ 0, "psrlw %RM,%EM", "psrld %RM,%EM", "psrlq %RM,%EM", "paddq %RM,%EM", "pmullw %RM,%EM", 0, "pmovmskb %Rd,%GM", "psubusb %RM,%EM", "psubusw %RM,%EM", "pminub %RM,%EM", "pand %RM,%EM", "paddusb %RM,%EM", "paddusw %RM,%EM", "pmaxub %RM,%EM", "pandn %RM,%EM", /* e */ "pavgb %RM,%EM", "psraw %RM,%EM", "psrad %RM,%EM", "pavgw %RM,%EM", "pmulhuw %RM,%EM", "pmulhw %RM,%EM", 0, "movntq %Myv,%RM", "psubsb %RM,%EM", "psubsw %RM,%EM", "pminsw %RM,%EM", "por %RM,%EM", "paddsb %RM,%EM", "paddsw %RM,%EM", "pmaxsw %RM,%EM", "pxor %RM,%EM", /* f */ 0, "psllw %RM,%EM", "pslld %RM,%EM", "psllq %RM,%EM", "pmuludq %RM,%EM", "pmaddwd %RM,%EM", "psadbw %RM,%EM", "maskmovq %GM,%RM", "psubb %RM,%EM", "psubw %RM,%EM", "psubd %RM,%EM", "psubq %RM,%EM", "paddb %RM,%EM", "paddw %RM,%EM", "paddd %RM,%EM", 0 }; char *second_f30f[]={ // 0 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 1 "movss %RX,%EX","movss %Md,%RX","movsldup %RX,%MX",0, 0,0,"movshdup %RX,%MX",0, 0,0,0,0,0,0,0,0, // 2 0,0,0,0, 0,0,0,0, 0, 0, "cvtsi2ss %RX,%Ed",0, "cvttss2si %Rd,%EX","cvtss2si %Rd,%EX",0, 0, // 3 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 4 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 5 0, "sqrtss %RX,%EX","rsqrtss %RX,%EX", "rcpss %RX,%EX", 0, 0, 0, 0, "addss %RX,%EX","mulss %RX,%EX", "cvtss2sd %RX,%EX","cvttps2dq %RX,%EX", "subss %RX,%EX","minss %RX,%EX", "divss %RX,%EX", "maxss %RX,%EX", // 6 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,"movdqu %RX,%EX", // 7 "pshufhw %RX,%EX,%Ib",0,0,0, 0,0,0,0, 0,0,0,0, 0,0,"movq %RX,%EX","movdqu %Md,%RX", // 8 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 9 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // a 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // b 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // c 0,0,"cmpss %RX,%EX,%Ib",0, 0,0,0, 0, 0,0,0, 0, 0,0,0, 0, // d 0,0,0,0, 0,0,"movq2dq RX,RM",0, 0,0,0,0,0,0,0,0, // e 0,0,0,0, 0,0,"cvtdq2pd %RX,%EX",0, 0,0,0,0,0,0,0,0, // f 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 }; char *second_f20f[]={ // 0 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 1 "movsd %RX,%Md","movsd %Md,%RX","movddup %RX,%MX",0, 0,0,0,0, 0,0,0,0,0,0,0,0, // 2 0,0,0,0, 0,0,0,0, 0,0,"cvtsi2sd %RX,%Md",0, "cvttsd2si %Rd,%EX","cvtsd2si %Rd,%EX",0,0, // 3 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 4 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 5 0,"sqrtsd %RX,%EX",0,0, 0,0,0,0, "addsd %RX,%EX","mulsd %RX,%MX","cvtsd2ss %RX,%EX",0, "subsd %RX,%EX","minsd %RX,%EX","divsd %RX,%EX","maxsd %RX,%EX", // 6 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 7 "pshuflw %RX,%EX,%Ib",0,0,0, 0,0,0,0, 0,0,0,0, "haddps %RX,%EX","hsubps %RX,%EX",0,0, // 8 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 9 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // a 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // b 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // c 0,0,"cmpsd %RX,%EX,%Ib",0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // d "addsubps %RX,%EX",0,0,0, 0,0,"movdq2q %RM,%RX",0, 0,0,0,0, 0,0,0,0, // e 0,0,0,0, 0,0,"cvtpd2dq %RX,%EX",0, 0,0,0,0,0,0,0,0, // f "lddqu %Md,%RX",0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; const char *second_660f[]={ // 0 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 1 "movupd %RX,%Md","movupd %Md,%RX","movlpd %RX,%Md","movlpd %Md,%RX", "unpcklpd %RX,%EX","unpckhpd %RX,%EX","movhpd %RX,%Md","movhpd %Md,%RX", 0,0,0,0, 0,0,0,0, // 2 0,0,0,0, 0,0,0,0, "movapd %RX,%EX", "movapd %Md,%RX", "cvtpi2pd %RX,%EM","movntpd %Md,%RX", "cvttpd2pi %RM,%EX","cvtpd2pi %RM,%EX","ucomisd %RX,%EX","comisd %RX,%EX", // 3 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 4 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 5 "movmskpd %Rd,%GX","sqrtpd %RX,%EX",0,0, "andpd %RX,%EX","andnpd %RX,%EX","orpd %RX,%MX","xorpd %RX,%EX", "addpd %RX,%EX","mulpd %RX,%MX","cvtpd2ps %RX,%EX","cvtps2dq %RX,%EX", "subpd %RX,%EX","minpd %RX,%EX","divpd %RX,%EX","maxpd %RX,%EX", // 6 "punpcklbw %RX,%EX", "punpcklwd %RX,%EX", "punpckldq %RX,%EX","packsswb %RX,%EX", "pcmpgtb %RX,%EX", "pcmpgtw %RX,%EX", "pcmpgtd %RX,%EX", "packuswb %RX,%EX", "punpckhbw %RX,%EX", "punpckhwd %RX,%EX", "punpckhdq %RX,%EX","packssdw %RX,%EX", "punpcklqdq %RX,%EX","punpckhqdq %RX,%EX","movd %RX,%Md", "movdqa %RX,%EX", // 7 "pshufd %RX,%EX,%Ib","%g3w %EX,%Ib", "%g3d %EX,%Ib","%g9", "pcmpeqb %RX,%EX", "pcmpeqw %RX,%EX", "pcmpeqd %RX,%EX",0, 0,0,0,0, "haddpd %RX,%EX","hsubpd %RX,%EX","movd %Md,%RX","movdqa %Md,%RX", // 8 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 9 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // a 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // b 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // c 0,0,"cmppd %RX,%EX,%Ib",0, "pinsrw %LX,%Fd,%Ib","pextrw %Gd,%RX,%Ib","shufpd %RX,%EX,%Ib",0, 0,0,0,0, 0,0,0,0, // d "addsubpd %RX,%EX","psrlw %RX,%EX", "psrld %RX,%EX", "psrlq %RX,%EX", "paddq %RX,%EX", "pmullw %RX,%EX", "movq %Md,%RX", "pmovmskb %Rd,%GX", "psubusb %RX,%EX", "psubusw %RX,%EX","pminub %RX,%EX","pand %RX,%EX", "paddusb %RX,%EX", "paddusw %RX,%EX","pmaxub %RX,%EX","pandn %RX,%EX", // e "pavgb %RX,%EX", "psraw %RX,%EX", "psrad %RX,%EX", "pavgw %RX,%EX", "pmulhuw %RX,%EX", "pmulhw %RX,%EX","cvttpd2dq %RX,%EX","movntdq %Md,%RX", "psubsb %RX,%EX", "psubsw %RX,%EX","pminsw %RX,%EX", "por %RX,%EX", "paddsb %RX,%EX", "paddsw %RX,%EX","pmaxsw %RX,%EX", "pxor %RX,%EX", // f 0, "psllw %RX,%EX", "pslld %RX,%EX", "psllq %RX,%EX", "pmuludq %RX,%EX", "pmaddwd %RX,%EX","psadbw %RX,%EX","maskmovdqu %RX,%RX", "psubb %RX,%EX", "psubw %RX,%EX", "psubd %RX,%EX", "psubq %RX,%EX", "paddb %RX,%EX", "paddw %RX,%EX", "paddd %RX,%EX", 0 }; char *groups[][8] = { /* group 0 is group 3 for %Ev set */ /* 0 */ { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }, /* 1 */ { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" }, /* 2 */ /* v v*/ { "test %Eq,%Iq", 0/*"test %Eq,%Iq"*/, "not %Ec", "neg %Ec", "mul %Ec", "imul %Ec", "div %Ec", "idiv %Ec" }, /* 3 */ { "inc %Eb", "dec %Eb", "psrl", 0, "psra", 0, "psll", 0 }, /* 4 */ { "inc %Ev", "dec %Ev", "call %Kn%Ev", "call %Kf%Ep", "jmp %Kn%Ev", "jmp %Kf%Ep", "push %Ev", 0 }, /* 5 */ { "sldt %Ew", "str %Ew", "lldt %Ew", "ltr %Ew", "verr %Ew", "verw %Ew", 0, 0 }, /* 6 */ { "sgdt %Ms", "sidt %Ms", "lgdt %Ms", "lidt %Ms", "smsw %Ew", 0, "lmsw %Ew", "invlpg %Em" }, /* 7 */ { "prefetchnta %Em","prefetcht0 %Em", "prefetcht1 %Em", "prefetcht2 %Em", "bt", "bts", "btr", "btc" }, /* 8 */ { "fxsave %Em", "fxrstor %Em", "ldmxcsr %Em", "stmxcsr %Em", 0, "lfence", "mfence", "%x2" }, /* 9 */ { 0,0,"psrlq %RX,%Ib","psrldq %RX,%Ib", 0,0,"psllq %RX,%Ib","pslldq %RX,%Ib" } }; /* zero here means invalid. If first entry starts with '*', use st(i) */ /* no assumed %EFs here. Indexed by RM(modrm()) */ char *f0[] = { 0, 0, 0, 0, 0, 0, 0, 0}; char *fop_9[] = { "*fxch st,%GF",0,0,0,0,0,0,0 }; char *fop_10[] = { "fnop", 0, 0, 0, 0, 0, 0, 0 }; char *fop_12[] = { "fchs", "fabs", 0, 0, "ftst", "fxam", 0, 0 }; char *fop_13[] = { "fld1", "fldl2t", "fldl2e", "fldpi", "fldlg2", "fldln2", "fldz", 0 }; char *fop_14[] = { "f2xm1", "fyl2x", "fptan", "fpatan", "fxtract", "fprem1", "fdecstp", "fincstp" }; char *fop_15[] = { "fprem", "fyl2xp1", "fsqrt", "fsincos", "frndint", "fscale", "fsin", "fcos" }; char *fop_21[] = { 0, "fucompp", 0, 0, 0, 0, 0, 0 }; char *fop_28[] = { "fneni", "fndisi", "fnclex", "fninit", "fnsetpm", 0, 0, 0 }; char *fop_32[] = { "*fadd %GF,st",0,0,0,0,0,0,0 }; char *fop_33[] = { "*fmul %GF,st",0,0,0,0,0,0,0 }; char *fop_36[] = { "*fsubr %GF,st",0,0,0,0,0,0,0 }; char *fop_37[] = { "*fsub %GF,st",0,0,0,0,0,0,0 }; char *fop_38[] = { "*fdivr %GF,st",0,0,0,0,0,0,0 }; char *fop_39[] = { "*fdiv %GF,st",0,0,0,0,0,0,0 }; char *fop_40[] = { "*ffree %GF",0,0,0,0,0,0,0 }; char *fop_42[] = { "*fst %GF",0,0,0,0,0,0,0 }; char *fop_43[] = { "*fstp %GF",0,0,0,0,0,0,0 }; char *fop_44[] = { "*fucom %GF",0,0,0,0,0,0,0 }; char *fop_45[] = { "*fucomp %GF",0,0,0,0,0,0,0 }; char *fop_48[] = { "*faddp %GF,st",0,0,0,0,0,0,0 }; char *fop_49[] = { "*fmulp %GF,st",0,0,0,0,0,0,0 }; char *fop_51[] = { 0, "fcompp", 0, 0, 0, 0, 0, 0 }; char *fop_52[] = { "*fsubrp %GF,st",0,0,0,0,0,0,0 }; char *fop_53[] = { "*fsubp %GF,st",0,0,0,0,0,0,0 }; char *fop_54[] = { "*fdivrp %GF,st",0,0,0,0,0,0,0 }; char *fop_55[] = { "*fdivp %GF,st",0,0,0,0,0,0,0 }; char *fop_60[] = { "fnstsw ax", 0, 0, 0, 0, 0, 0, 0 }; char *fop_16[]={"*fcmovb st,%GF",0,0,0,0,0,0,0}; char *fop_17[]={"*fcmove st,%GF",0,0,0,0,0,0,0}; char *fop_18[]={"*fcmovbe st,%GF",0,0,0,0,0,0,0}; char *fop_19[]={"*fcmovu st,%GF",0,0,0,0,0,0,0}; char *fop_24[]={"*fcmovnb st,%GF",0,0,0,0,0,0,0}; char *fop_25[]={"*fcmovne st,%GF",0,0,0,0,0,0,0}; char *fop_26[]={"*fcmovnbe st,%GF",0,0,0,0,0,0,0}; char *fop_27[]={"*fcmovnu st,%GF",0,0,0,0,0,0,0}; char *fop_29[]={"*fucomi st,%GF",0,0,0,0,0,0,0}; char *fop_30[]={"*fcomi st,%GF",0,0,0,0,0,0,0}; char *fop_61[]={"*fucomip st,%GF",0,0,0,0,0,0,0}; char *fop_62[]={"*fcomip st,%GF",0,0,0,0,0,0,0}; char **fspecial[] = { /* 0=use st(i), 1=undefined 0 in fop_* means undefined */ 0, 0, 0, 0, 0, 0, 0, 0, 0, fop_9, fop_10, 0, fop_12, fop_13, fop_14, fop_15, fop_16, fop_17, fop_18, fop_19, f0, fop_21, f0, f0, fop_24, fop_25, fop_26, fop_27, fop_28, fop_29, fop_30, f0, fop_32, fop_33, f0, f0, fop_36, fop_37, fop_38, fop_39, fop_40, f0, fop_42, fop_43, fop_44, fop_45, f0, f0, fop_48, fop_49, f0, fop_51, fop_52, fop_53, fop_54, fop_55, f0, f0, f0, f0, fop_60, fop_61, fop_62, f0 }; char *floatops[] = { /* assumed " %EF" at end of each. mod != 3 only */ /*00*/ "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", /*08*/ "fld", 0, "fst", "fstp", "fldenv", "fldcw", "fnstenv", "fnstcw", /*16*/ "fiadd", "fimul", "ficomw", "ficompw", "fisub", "fisubr", "fidiv", "fidivr", /*24*/ "fild", 0, "fist", "fistp", "frstor", "fldt", 0, "fstpt", /*32*/ "faddq", "fmulq", "fcomq", "fcompq", "fsubq", "fsubrq", "fdivq", "fdivrq", /*40*/ "fldq", 0, "fstq", "fstpq", 0, 0, "fnsave", "fnstsw", /*48*/ "fiaddw", "fimulw", "ficomw", "ficompw", "fisubw", "fisubrw", "fidivw", "fidivr", /*56*/ "fildw", 0, "fistw", "fistpw", "fbldt", "fildq", "fbstpt", "fistpq" }; /* variables controlled by command line flags */ unsigned char seg_size=16; /* default size is 16 */ unsigned char must_do_size; unsigned int wordop,qwordop; /* dealing with word or byte operand */ unsigned long instruction_offset; unsigned short done_space; /* for opcodes with > one space */ char ubuf[100],*ubufp; int col; /* output column */ unsigned int prefix; /* segment override prefix byte */ unsigned int modrmv; /* flag for getting modrm byte */ unsigned int sibv; /* flag for getting sib byte */ unsigned int opsize; /* just like it says ... */ unsigned int addrsize; void printbyte(unsigned char c) { if(c<10)uprintf("%u",(unsigned char)c); else if(c<16||c>0x9F)uprintf("0%Xh",(unsigned char)c); else uprintf("%Xh",(unsigned char)c); } void printword(unsigned short c) { if(c<256)printbyte(c); else if(c<0xA00||(c>0xFFF&&c<0xA000))uprintf("%Xh",c); else uprintf("0%Xh",c); } void printdword(unsigned int c) { if(c<65536)printword((unsigned short)c); else if(c<0xA0000L||(c>0xFFFFFL&&c<0xA00000L)||(c>0xFFFFFFL&&c<0xA000000L)|| (c>0xFFFFFFFL&&c<0xA0000000L))uprintf("%lXh",c); else uprintf("0%lXh",c); } void addr_to_hex(long addr, unsigned char splitup) { static char buffer[25]; WORD32 adr; adr.dword=addr; if(splitup){ if(adr.w.seg==0/*||adr.w.seg==0xffff*/)printword(adr.w.ofs);//sprintf(buffer,"%04Xh",adr.w.ofs); else{ sprintf(buffer,"%04Xh:%04Xh",adr.w.seg,adr.w.ofs); uprintf("%s",buffer); } } else{ if(adr.w.seg==0/*||adr.w.seg==0xffff*/)printword(adr.w.ofs);//sprintf(buffer,"%04Xh",adr.w.ofs); else printdword(addr);//sprintf(buffer, "%08lXh",addr); } } unsigned char getbyte(void) { short c; c=output[outptr++]; fprintf(hout,"%02X", c); /* print out byte */ col+=2; instruction_offset++; return c; } int modrm() { if (modrmv == -1) modrmv = getbyte(); return modrmv; } int sib() { if (sibv == -1) sibv = getbyte(); return sibv; } /*------------------------------------------------------------------------*/ void uprintf(char *s, ...) { va_list argptr; va_start(argptr,s); vsprintf(ubufp,s,argptr); va_end(argptr); while (*ubufp) ubufp++; } void uputchar(char c) { if (c == '\t') { if(done_space)uputchar(' '); else { done_space=1; do { *ubufp++ = ' '; } while ((ubufp-ubuf) % 8); } } else *ubufp++ = c; *ubufp = 0; } /*------------------------------------------------------------------------*/ int bytes(char c) { switch (c){ case 'b': return 1; case 'w': return 2; case 'd': return 4; case 'v': if (opsize == 32) return 4; else return 2; } return 0; } /*------------------------------------------------------------------------*/ void outhex(char subtype, int extend, int optional, int defsize, int sign) { int n=0, s=0, i; long delta; unsigned char buff[6]; //char *name; char signchar; switch (subtype) { case 'q': if (wordop) { if (opsize==16) n = 2; else n = 4; } else n = 1; break; case 'a': break; case 'x': extend = defsize/8;//2; n = 1; break; case 'b': n = 1; break; case 'w': n = 2; break; case 'd': n = 4; break; case 's': n = 6; break; case 'c': case 'v': if (defsize == 32) n = 4; else n = 2; break; case 'p': if (defsize == 32) n = 6; else n = 4; s = 1; break; } for (i=0; i n) { if (subtype!='x') { if ((long)delta<0) { delta = -delta; signchar = '-'; } else signchar = '+'; if (delta || !optional){ uprintf("%c",signchar); printdword(delta); // uprintf("%c%0*lXh", signchar, extend+1, delta); } } else { if (extend==2) delta = (unsigned short) delta; printdword(delta); // uprintf("%0.*lXh", 2*extend+1, delta); } return; } if ((n == 4) && !sign) { addr_to_hex(delta, 0); return; } switch (n) { case 1: if (sign && (char)delta<0) { delta = -delta; signchar = '-'; } else signchar = '+'; if(sign)uprintf("%c",signchar); printbyte((unsigned char)delta); // if (sign)uprintf("%c%03Xh",signchar,(unsigned char)delta); // else uprintf("%03Xh", (unsigned char)delta); break; case 2: if (sign && (int)delta<0) { signchar = '-'; delta = -delta; } else signchar = '+'; if(sign)uprintf("%c",signchar); printword((unsigned short)delta); // if (sign) uprintf("%c%05Xh", signchar,(int)delta); // else uprintf("%05Xh", (unsigned int)delta); break; case 4: if (sign && (long)delta<0) { delta = -delta; signchar = '-'; } else signchar = '+'; if(sign)uprintf("%c",signchar); printdword(delta); // if (sign)uprintf("%c%09lXh", signchar, (unsigned long)delta); // else uprintf("%09lXh", (unsigned long)delta); break; } } /*------------------------------------------------------------------------*/ void reg_name(int regnum, char size) { if (size == 'F') { /* floating point register? */ uprintf("st(%d)", regnum); return; } if (size == 'M') { /* multimedia register? */ uprintf("mm%d", regnum); return; } if(size=='X'){ /* xmm register? */ uprintf("xmm%d",regnum); return; } if (((size == 'v') && (opsize == 32)) || (size == 'd')|| ((size=='c'||size=='q')&&wordop&&opsize==32) ) uputchar('e'); // printf("size=%c wordop=%d opsize=%d\n",size,wordop,opsize); if(size=='b'||((size=='q'||size=='c')&&!wordop)){ uputchar("acdbacdb"[regnum]); uputchar("llllhhhh"[regnum]); } else { uputchar("acdbsbsd"[regnum]); uputchar("xxxxppii"[regnum]); } } /*------------------------------------------------------------------------*/ void do_sib(int m) { int s, i, b; s = SCALE(sib()); i = INDEX(sib()); b = BASE(sib()); switch (b) { /* pick base */ case 0: ua_str("%p:[eax"); break; case 1: ua_str("%p:[ecx"); break; case 2: ua_str("%p:[edx"); break; case 3: ua_str("%p:[ebx"); break; case 4: ua_str("%p:[esp"); break; case 5: if (m == 0) { ua_str("%p:["); outhex('d', 4, 0, addrsize, 0); } else ua_str("%p:[ebp"); break; case 6: ua_str("%p:[esi"); break; case 7: ua_str("%p:[edi"); break; } switch (i) { /* and index */ case 0: uprintf("+eax"); break; case 1: uprintf("+ecx"); break; case 2: uprintf("+edx"); break; case 3: uprintf("+ebx"); break; case 4: break; case 5: uprintf("+ebp"); break; case 6: uprintf("+esi"); break; case 7: uprintf("+edi"); break; } if (i != 4) { switch (s) { /* and scale */ case 0: uprintf(""); break; case 1: uprintf("*2"); break; case 2: uprintf("*4"); break; case 3: uprintf("*8"); break; } } } /*------------------------------------------------------------------------*/ void do_modrm(char subtype) { int mod = MOD(modrm()); int rm = RM(modrm()); int extend = (addrsize == 32) ? 4 : 2; if (mod == 3) { /* specifies two registers */ reg_name(rm, subtype); return; } if (must_do_size) { if(qwordop)ua_str("qword ptr "); else{ if (wordop) { if (/*addrsize==32 ||*/ opsize==32) { /* then must specify size */ ua_str("dword ptr "); } else ua_str("word ptr "); } else ua_str("byte ptr "); } } if ((mod == 0) && (rm == 5) && (addrsize == 32)) {/* mem operand with 32 bit ofs */ ua_str("%p:["); outhex('d', extend, 0, addrsize, 0); uputchar(']'); return; } if ((mod == 0) && (rm == 6) && (addrsize == 16)) { /* 16 bit dsplcmnt */ ua_str("%p:["); outhex('w', extend, 0, addrsize, 0); uputchar(']'); return; } if ((addrsize != 32) || (rm != 4)) ua_str("%p:["); if (addrsize == 16) { switch (rm) { case 0: uprintf("bx+si"); break; case 1: uprintf("bx+di"); break; case 2: uprintf("bp+si"); break; case 3: uprintf("bp+di"); break; case 4: uprintf("si"); break; case 5: uprintf("di"); break; case 6: uprintf("bp"); break; case 7: uprintf("bx"); break; } } else { switch (rm) { case 0: uprintf("eax"); break; case 1: uprintf("ecx"); break; case 2: uprintf("edx"); break; case 3: uprintf("ebx"); break; case 4: do_sib(mod); break; case 5: uprintf("ebp"); break; case 6: uprintf("esi"); break; case 7: uprintf("edi"); break; } } switch (mod) { case 1: outhex('b', extend, 1, addrsize, 0); break; case 2: outhex('v', extend, 1, addrsize, 1); break; } uputchar(']'); } /*------------------------------------------------------------------------*/ void floating_point(int e1) { int esc = e1*8 + REG(modrm()); if(MOD(modrm())==3){ //2-\89 \81\80\89\92>C0 if (fspecial[esc]) { if (fspecial[esc][0]!=NULL&&fspecial[esc][0][0] == '*')ua_str(fspecial[esc][0]+1); else ua_str(fspecial[esc][RM(modrm())]); } else { ua_str(floatops[esc]); ua_str(" %EF"); } } else { ua_str(floatops[esc]); ua_str(" %EF"); } } /*------------------------------------------------------------------------*/ /* Main table driver */ void percent(char type, char subtype) { long vofs; int extend =(addrsize==32)?4:2; unsigned char c; switch (type) { case 'A': /* direct address */ outhex(subtype,extend,0,addrsize,0); break; case 'C': /* reg(r/m) picks control reg */ uprintf("CR%d",REG(modrm())); must_do_size=0; break; case 'D': /* reg(r/m) picks debug reg */ uprintf("DR%d", REG(modrm())); must_do_size = 0; break; case 'E': /* r/m picks operand */ if(subtype=='m')must_do_size=0; do_modrm(subtype); break; case 'F': if(MOD(modrm())!=3)do_modrm(subtype); else reg_name(REG(modrm()),subtype); break; case 'G': /* reg(r/m) picks register */ /* if (subtype == 'F'||subtype == 'M') reg_name(RM(modrm()), subtype); else reg_name(REG(modrm()), subtype);*/ reg_name(RM(modrm()),subtype); must_do_size = 0; break; case 'I': /* immed data */ outhex(subtype, 0, 0, opsize, 0); break; case 'J': /* relative IP offset */ switch(bytes(subtype)) { /* sizeof offset value */ case 1: vofs=(signed char)getbyte(); break; case 2: vofs = getbyte(); vofs += getbyte()<<8; vofs = (short)vofs; break; case 4: vofs = (unsigned long)getbyte(); /* yuk! */ vofs |= (unsigned long)getbyte() << 8; vofs |= (unsigned long)getbyte() << 16; vofs |= (unsigned long)getbyte() << 24; break; } addr_to_hex(vofs+instruction_offset,seg_size==16?(unsigned char)1:(unsigned char)0); break; case 'K': if(seg_size==16){ switch(subtype){ case 'f': ua_str("far "); break; case 'n': ua_str("near "); break; case 's': ua_str("short "); break; } } else if(subtype=='s')ua_str("short "); break; case 'L': if(MOD(modrm())!=3)reg_name(REG(modrm()),subtype); else reg_name(RM(modrm()),subtype); break; case 'M': /* r/m picks memory */ do_modrm(subtype); break; case 'O': /* offset only */ ua_str("%p:["); outhex(subtype, extend, 0, addrsize, 0); uputchar(']'); break; case 'P': /* prefix byte (rh) */ ua_str("%p:"); break; case 'R': /* mod(r/m) picks register */ reg_name(REG(modrm()), subtype); /* rh */ must_do_size = 0; break; case 'S': /* reg(r/m) picks segment reg */ uputchar("ecsdfg"[REG(modrm())]); uputchar('s'); must_do_size = 0; break; case 'T': /* reg(r/m) picks T reg */ uprintf("tr%d", REG(modrm())); must_do_size = 0; break; case 'X': /* ds:si type operator */ uprintf("ds:["); if (addrsize == 32) uputchar('e'); uprintf("si]"); break; case 'Y': /* es:di type operator */ uprintf("es:["); if (addrsize == 32) uputchar('e'); uprintf("di]"); break; case '2': c=getbyte(); /* old [pop cs]! now indexes */ wordop = c & 1; ua_str(second[c]); /* instructions in 386/486 */ break; case 'd': /* sizeof operand==dword? */ if (opsize == 32) uputchar('d'); uputchar(subtype); break; case 'e': /* extended reg name */ if (opsize == 32) { if (subtype == 'w')uputchar('d'); else { uputchar('e'); uputchar(subtype); } } else uputchar(subtype); break; case 'f': /* '87 opcode */ floating_point(subtype-'0'); break; case 'j': if (/*addrsize==32 ||*/ opsize==32) /* both of them?! */ uputchar('e'); break; case 'g': /* modrm group `subtype' (0--7) */ switch(subtype){ case '9': vofs=REG(modrm()); modrmv=(modrmv&0xC7)|((modrmv&7)<<3); ua_str(groups[9][vofs]); break; case '6': if(MOD(modrm())!=3)goto defg; switch(modrmv){ case 0xc8: ua_str("monitor"); break; case 0xc9: ua_str("mwait"); break; default: uprintf(""); break; } break; case '5': opsize=16; case '7': wordop=1; default: defg: ua_str(groups[subtype-'0'][REG(modrm())]); break; } break; case 'p': /* prefix byte */ switch (subtype) { case 'c': case 'd': case 'e': case 'f': case 'g': case 's': prefix = subtype; c = getbyte(); wordop = c & 1; ua_str(opmap1[c]); break; case ':': if (prefix) uprintf("%cs:", prefix); break; case ' ': c = getbyte(); wordop = c & 1; ua_str(opmap1[c]); break; } break; case 's': /* size override */ switch (subtype) { case 'a': addrsize = 48 - addrsize; c = getbyte(); wordop = c & 1; ua_str(opmap1[c]); break; case 'o': opsize = 48 - opsize; c = getbyte(); wordop = c & 1; ua_str(opmap1[c]); break; } break; case 'w': /* insert explicit size specifier */ if (opsize == 32)uputchar('d'); else uputchar('w'); uputchar(subtype); break; case 'x': if(MOD(modrm())==3){ switch(subtype-'0'){ case 0: ua_str("movhlps %RX,%GX"); break; case 1: ua_str("movlhps %RX,%GX"); break; case 2: ua_str("sfence"); break; } } else{ switch(subtype-'0'){ case 0: ua_str("movlps %RX,%Md"); break; case 1: ua_str("movhps %RX,%Md"); break; case 2: ua_str("clflush %Em"); break; } } break; default: preerror("uncnown operand for dizassemler"); break; } } void ua_str(char *str) { char c; if (str == NULL) { uprintf(""); return; } if (strpbrk(str, "CDFGRST")) /* specifiers for registers=>no size 2b specified */ must_do_size = 0; while ((c = *str++) != 0) { if (c == '%') { c = *str++; if(*str=='y'){ qwordop=1; str++; } percent(c,*str++); } else { if (c == ' ') uputchar('\t'); else uputchar(c); } } } void unassemble(unsigned long ofs) { char *str; int c; fprintf(hout,seg_size==16?"%04X ":"%08lX ",ofs); prefix = 0; modrmv = sibv = 0xFFFFFFFF; /* set modrm and sib flags */ opsize = addrsize = seg_size; col = 0; ubufp = ubuf; done_space = 0; c = getbyte(); if(c==0x9B){ switch(*(short *)&output[outptr]){ case 0xE0DB: case 0xE1DB: case 0xE2DB: case 0xE3DB: case 0xE4DB: getbyte(); c=getbyte(); switch(c){ case 0xE0: ua_str("feni"); break; case 0xE1: ua_str("fdisi"); break; case 0xE2: ua_str("fclex"); break; case 0xE3: ua_str("finit"); break; case 0xE4: ua_str("fsetpm"); break; } goto endp; } } else if(c==0x98){ if(am32){ ua_str("cwde"); goto endp; } } else if(c==0x99){ if(am32){ ua_str("cdq"); goto endp; } } else if(c==0x66&&am32==0){ if(output[outptr]==0x98){ ua_str("cwde"); getbyte(); goto endp; } if(output[outptr]==0x99){ ua_str("cdq"); getbyte(); goto endp; } } else if(c==0xF3&&output[outptr]==0x90){ ua_str("pause"); getbyte(); goto endp; } if(output[outptr]==0x0f){ int c2=output[outptr+1]; switch(c){ case 0x66: if(second_660f[c2]){ getbyte(); ua_str((char *)second_660f[getbyte()]); goto endp; } break; case 0xf2: if(second_f20f[c2]){ getbyte(); ua_str(second_f20f[getbyte()]); goto endp; } break; case 0xf3: if(second_f30f[c2]){ getbyte(); ua_str(second_f30f[getbyte()]); goto endp; } break; } } wordop = c & 1; qwordop=0; must_do_size = 1; if ((str = opmap1[c])==NULL) { /* invalid instruction? */ uputchar('d'); /* then output byte defines */ uputchar('b'); uputchar('\t'); uprintf("%02Xh",c); } else ua_str(str); /* valid instruction */ endp: fprintf(hout,"%*s", 25-col, " "); fprintf(hout,"%s\n", ubuf); } #define MAXSTR 12 void undata(unsigned ofs,unsigned long len,unsigned int type) { unsigned int sizet,c,i,j; unsigned long total,d; unsigned char data[MAXSTR]; if(type==3)sizet=1; else sizet=type; for(total=0;totallen){ type=sizet=1; } for(i=0;ilen)break; if(sizet==8)break; } uputchar(sizet==8?'q':'d'); switch(sizet){ case 1: uputchar('b'); break; case 2: case 8: uputchar('w'); break; case 4: uputchar('d'); break; } done_space=0; uputchar('\t'); switch(type){ case 1: for(j=0;j=0x20){ if(c==0){ c++; if(j!=0)uputchar(','); uputchar(0x27); } uputchar(data[j]); } else{ if(c!=0){ c=0; uputchar(0x27); } if(j!=0)uputchar(','); printbyte(data[j]); } } if(c)uputchar(0x27); break; case 4: for(j=0;j