{ $Id$ } { --------------------------------------------------------------------------- fpdbgdisasx86.pp - Native Freepascal debugger - x86 Disassembler --------------------------------------------------------------------------- This unit contains a x86 disassembler for the Native Freepascal debugger --------------------------------------------------------------------------- @created(Mon Apr 22th WET 2006) @lastmod($Date$) @author(Marc Weustink ) *************************************************************************** * * * This source 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; either version 2 of the License, or * * (at your option) any later version. * * * * This code 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. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** } unit FpDbgDisasX86; {$mode objfpc}{$H+} interface {.$define debug_OperandSize} {.$define verbose_string_instructions} uses SysUtils, FpDbgUtil, FpDbgInfo, DbgIntfBaseTypes, FpdMemoryTools, FpDbgClasses, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazClasses; { The function Disassemble decodes the instruction at the given address. After decoding, the address increased to the next instruction. The following chars are used to indicate problems with instruction sequenses: ** invalid opcode -- reserved opcode () ignored opcode ?? unspecified !! internal error, a group got called for an opcode which wasn't decoded there The disassembler starts to decode the first byte according to Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2: Table A-2. One-byte Opcode Map: (00H — F7H) and Table A-2. One-byte Opcode Map: (08H — FFH) The 3DNow!(tm) instructions are decoded according to AMD64 Architecture Programmer’s Manual Volume 3: Table A-13. Immediate Byte for 3DNow!(tm) Opcodes, Low Nibble 0–7h and Table A-14. Immediate Byte for 3DNow!(tm) Opcodes, Low Nibble 8–Fh The routines Addxx use the same abbriviations as used in those tables } type // rexB, rexX, rexR, rexW see // Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2: // Table 2-4. REX Prefix Fields [BITS: 0100WRXB] TFlag = ( flagRex, // $4x: set for any $4X flagSib, flagModRM, rexB, // $4x bit 0: Extension of the ModR/M r/m field, SIB base field, or Opcode reg field rexX, // $4x bit 1: Extension of the SIB index field rexR, // $4x bit 2: Extension of the ModR/M reg field rexW, // $4x bit 3: 64 Bit Operand Size pre66, // $66: Operand-size override prefix (32 and 64 bit) or SIMD prefix preAdr, // $67: Address-size override prefix preLock, preF2, // $F2: Repeat string/input/output or SIMD prefix preF3, // $F3: Repeat string/input/output or SIMD prefix oprDefault64, // In 64bit mode set default operand size to 64 (d64 note in Table A-x) oprForce64, // In 64bit mode set operand size to 64 (f64 note in Table A-x) flagVex, vexL, vexW, vexX, vexB ); TFlags = set of TFlag; // Keep 8,16,32,64 together TOperandSize = (os8, os16, os32, os64, os48, os80, os128); TAddressSize = (as16, as32, as64); TRegisterType = (reg0, reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug, regX87); TModRMType = (modReg, modMem); TModRMTypes = set of TModRMType; TSimdOpcode = (soInvalid, soNone, so66, soF2, soF3); TInstructionFlag = ( ifOnly32, ifOnly64, ifPrefixLock, ifPrefixRep, ifPrefixRepE, ifPrefixRepNe ); TOpCode = ( OPX_InternalUnknown, OPX_Invalid, OPX_InvalidX87, OPX_ReservedX87, OPX_Not87, OPX_3dnow, OPX_Group1a, OPX_NotGroup1, OPX_NotGroup2, OPX_NotGroup3, OPX_Group4, OPX_NotGroup4, OPX_Group5, OPX_NotGroup5, OPX_Group6, OPX_NotGroup6, OPX_Group7, OPX_NotGroup7, OPX_Group8, OPX_NotGroup8, OPX_Group9, OPX_NotGroup9, OPX_Group10, OPX_NotGroup10, OPX_Group11, OPX_NotGroup11, OPX_Group12, OPX_NotGroup12, OPX_Group13, OPX_NotGroup13, OPX_Group14, OPX_NotGroup14, OPX_Group15, OPX_NotGroup15, OPX_Group16, OPX_NotGroup16, OPX_GroupP, OPX_NotGroupP, OPXsysenter, OPXsysexit, OPfadd, OPfmul, OPfcom, OPfcomp, OPfsub, OPfsubr, OPfdiv, OPfdivr, OPfld, OPfxch, OPfst, OPfstp, OPfldenv, OPfldcw, OPfnstenv, OPfnstcw, OPfchs, OPfabs, OPftst, OPfxam, OPfld1, OPfldl2t, OPfldl2e, OPfldpi, OPfldlg2, OPfldln2, OPfldz, OPf2xm1, OPfyl2x, OPfptan, OPfpatan, OPfxtract, OPfprem1, OPfdecstp, OPfincstp, OPfprem, OPfyl2xp1, OPfsqrt, OPfsincos, OPfrndint, OPfscale, OPfsin, OPfcos, OPnop, OPfiadd, OPfimull, OPficom, OPficomp, OPfisub, OPfisubr, OPfidiv, OPfidivr, OPfcmovb, OPfcmove, OPfcmovbe, OPfcmovu, OPfucompp, OPfild, OPfisttp, OPfist, OPfistp, OPfcmovnb, OPfcmovne, OPfcmovnbe, OPfcmovnu, OPfucomi, OPfcomi, OPfnclex, OPfninit, OPfrstor, OPfnsave, OPfnstsw, OPffree, OPfucomp, OPfaddp, OPfmullp, OPfsubrp, OPfsubp, OPfdivrp, OPfdivp, OPfbld, OPfbstp, OPfcompp, OPfucomip, OPfcomip, OPpi2fw, OPpi2fd, OPpf2iw, OPpf2id, OPpfnacc, OPpfpnacc, OPpfcmpge, OPpfmin, OPpfrcp, OPpfrsqrt, OPpfsub, OPpfadd, OPpgcmpgt, OPpfmax, OPpfrcpit1, OPpfrsqit1, OPpfsubr, OPpfacc, OPpfcmpeq, OPpfmul, OPpfrcpit2, OPpmulhrw, OPpswapd, OPpavgusb, OPadd, OPor, OPadc, OPsbb, OPand, OPsub, OPxor, OPcmp, OPpop, OProl, OPror, OPrcl, OPrcr, OPshl, OPshr, OPsal, OPsar, OPtest, OPnot, OPneg, OPmul, OPimul, OPdiv, OPidiv, OPinc, OPdec, OPcall, OPjmp, OPpush, OPsldt, OPstr, OPlldt, OPltr, OPverr, OPverw, OPvmrun, OPvmmcall, OPvmload, OPvmsave, OPstgi, OPclgi, OPskinit, OPinvlpga, OPsgdt, OPsidt, OPlgdt, OPlidt, OPsmsw, OPlmsw, OPswapgs, OPrdtscp, OPinvlpg, OPbts, OPbtr, OPbtc, OPbt, OPcmpxchg16b, OPcmpxchg8b, OPmov, OPpsrlw, OPpsraw, OPpsllw, OPpsrld, OPpsrad, OPpslld, OPpsrlq, OPpsrldq, OPpsllq, OPfxsave, OPfxrstor, OPldmxcsr, OPstmxcsr, OPlfence, OPmfence, OPclflush, OPprefetch_exclusive, OPprefetch_modified, OPX_prefetch, OPpunpcklbw, OPpunpcklwd, OPpunpcklqd, OPpacksswb, OPpcmpgtb, OPpcmpgtw, OPpcmpgtd, OPpackuswb, OPpunpkhbw, OPpunpkhwd, OPpunpkhdq, OPpackssdw, OPpunpcklqdq, OPpunpckhqdq, OPpaddq, OPpmullw, OPpsubusb, OPpsubusw, OPpminub, OPpand, OPpaddusb, OPpaddusw, OPpmaxub, OPpandn, OPpavgb, OPpavgw, OPpmulhuw, OPpmulhw, OPpsubsb, OPpsubsw, OPpminsw, OPpor, OPpaddsb, OPpaddsw, OPpmaxsw, OPpxor, OPpmuludq, OPpmaddwd, OPpsadbw, OPpsubb, OPpsubw, OPpsubd, OPpsubq, OPpaddb, OPpaddw, OPpaddd, OPlar, OPlsl, OPsyscall, OPclts, OPsysret, OPinvd, OPwbinvd, OPud2, OPfemms, OPmovups, OPmovss, OPmovupd, OPmovsd, OPmovhlps, OPmovsldup, OPmovlpd, OPmovddup, OPmovlps, OPunpcklps, OPunpcklpd, OPunpckhps, OPunpckhpd, OPmovlhps, OPmovshdup, OPmovhpd, OPmovhps, OPmovaps, OPmovapd, OPcvtpi2ps, OPcvtsi2ss, OPcvtpi2pd, OPcvtsi2sd, OPmovntps, OPmovntpd, OPcvttps2pi, OPcvttss2si, OPcvttpd2pi, OPcvttsd2si, OPcvtps2pi, OPcvtss2si, OPcvtpd2pi, OPcvtsd2si, OPucomiss, OPucomissd, OPcomiss, OPcomissd, OPwrmsr, OPrdtsc, OPrdmsr, OPrdpmc, OPcmov__, OPmovmskps, OPmovmskpd, OPsqrtps, OPsqrtss, OPsqrtpd, OPsqrtsd, OPaddps, OPaddss, OPaddpd, OPaddsd, OPmulps, OPmulss, OPmulpd, OPmulsd, OPsubps, OPsubss, OPsubpd, OPsubsd, OPminps, OPminss, OPminpd, OPminsd, OPdivps, OPdivss, OPdivpd, OPdivsd, OPmaxps, OPmaxss, OPmaxpd, OPmaxsd, OPrsqrtps, OPrsqrtss, OPrcpps, OPrcpss, OPandps, OPandpd, OPandnps, OPandnpd, OPorps, OPorpd, OPxorps, OPxorpd, OPcvtps2pd, OPcvtss2sd, OPcvtpd2ps, OPcvtsd2ss, OPcvtdq2ps, OPcvttps2dq, OPcvtps2dq, OPmovd, OPmovq, OPmovdqu, OPmovdqa, OPpshufw, OPpshufhw, OPpshufd, OPpshuflw, OPpcmpeqb, OPpcmpeqw, OPpcmpeqd, OPemms, OPhaddpd, OPhaddps, OPhsubpd, OPhsubps, OPj__, OPset__, OPcpuid, OPshld, OPrsm, OPshrd, OPcmpxchg, OPlss, OPlfs, OPlgs, OPmovzx, OPbsf, OPbsr, OPmovsx, OPxadd, OPcmpps, OPcmpss, OPcmppd, OPcmpsd, OPmovnti, OPpinsrw, OPpextrw, OPshufps, OPshufpd, OPbswp, OPaddsubpd, OPaddsubps, OPmovq2dq, OPmovdq2q, OPpmovmskb, OPcvtdq2pd, OPcvttpd2dq, OPcvtpd2dq, OPmovntq, OPmovntdqu, OPlddqu, OPmaskmovq, OPmaskmovdqu, OPdaa, OPdas, OPaaa, OPaas, OPpusha, OPpushad, OPpopa, OPpopad, OPbound, OPmovsxd, OParpl, OPinsb, OPinsw, OPinsd, OPoutsb, OPoutsw, OPoutsd, OPxchg, OPlea, OPcdqe, OPcwde, OPcbw, OPcqo, OPcqd, OPcwd, OPwait_fwait, OPpushfq, OPpushfd, OPpushf, OPpopfq, OPpopfd, OPpopf, OPsahf, OPlahf, OPmovsb, OPmovsq, OPmovsw, OPcmpsb, OPcmpsq, OPcmpsw, OPstosb, OPstosq, OPstosd, OPstosw, OPlodsb, OPlodsq, OPlodsd, OPlodsw, OPscasb, OPscasq, OPscasd, OPscasw, OPret, OPles, OPlds, OPenter, OPleave, OPretf, OPint3, OPint, OPint0, OPiretq, OPiretd, OPiret, OPaam, OPaad, OPsalc, OPxlat, OPloopne, OPloope, OPloop, OPjrcxz, OPin, OPout, OPint1, OPhlt, OPcmc, OPclc, OPstc, OPcli, OPsti, OPcld, OPstd ); TOpCodeSuffix = ( OPSx_none, // Condition OPSx_o, OPSx_no, OPSx_b, OPSx_nb, OPSx_z, OPSx_nz, OPSx_be, OPSx_nbe, OPSx_s, OPSx_ns, OPSx_p, OPSx_np, OPSx_l, OPSx_nl, OPSx_le, OPSx_nle ); TOperandFlag = (ofMemory); TOperandFlags = set of TOperandFlag; TInstruction = record OpCode: TOpCode; OpCodeSuffix: TOpCodeSuffix; Flags: set of TInstructionFlag; Segment: String; Operand: array[1..4] of record CodeIndex: integer; Value: String; Size: TOperandSize; ByteCount: Byte; ByteCount2: Byte; FormatFlags: THexValueFormatFlags; Flags: TOperandFlags; end; OperCnt: Integer; ParseFlags: TFlags; end; PInstruction = ^TInstruction; { TX86Disassembler } TX86Disassembler = object private ProcessMode: TFPDMode; Code: PByte; CodeIdx: Byte; OperIdx: Integer; ModRMIdx: Byte; Flags: TFlags; SimdOpcode: TSimdOpcode; //--- result --- Instruction: PInstruction; //--- add operands --- // the the Zz as used in AddZz routines are encoded according to: // // Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2: // A.2 KEY TO ABBREVIATIONS // // and // // AMD64 Architecture Programmer’s Manual Volume 3: // Appendix A Opcode and Operand Encodings // //--- procedure AddAp; procedure AddCd_q; procedure AddDd_q; procedure AddEb; procedure AddEd; procedure AddEd_q; procedure AddEv; procedure AddEw; procedure AddFv; procedure AddGb; procedure AddGd; procedure AddGd_q; procedure AddGv; procedure AddGw; procedure AddGz; procedure AddIb; procedure AddIv; procedure AddIw; procedure AddIz; procedure AddJb; procedure AddJz; procedure AddM; procedure AddMa; procedure AddMb; procedure AddMd; procedure AddMdq; procedure AddMd_q; procedure AddMp; procedure AddMq; procedure AddMs; procedure AddMw_Rv; procedure AddOb; procedure AddOv; procedure AddPd_q; procedure AddPq; procedure AddPRq; procedure AddQd; procedure AddQq; procedure AddRd_q; procedure AddSw; procedure AddVdq; procedure AddVdq_sd; procedure AddVdq_ss; procedure AddVd_q; procedure AddVpd; procedure AddVps; procedure AddVq; procedure AddVRdq; procedure AddVRpd; procedure AddVRps; procedure AddVRq; procedure AddVsd; procedure AddVss; procedure AddWdq; procedure AddWpd; procedure AddWps; procedure AddWq; procedure AddWsd; procedure AddWss; {$ifdef verbose_string_instructions} procedure AddXb; procedure AddXv; procedure AddXz; procedure AddYb; procedure AddYv; procedure AddYz; {$endif} //--- procedure AddModReg; procedure AddModReg(AType: TRegisterType); procedure AddModReg(AType: TRegisterType; ASize: TOperandSize); procedure AddModRM(AReqTypes: TModRMTypes; ASize: TOperandSize; AType: TRegisterType); procedure AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Byte=0; AFormatFlags: THexValueFormatFlags=[]; AFlags: TOperandFlags=[]; AByteCount2: Byte=0); procedure AddOperand(const AValue: String; AByteCount: Byte=0; AFormatFlags: THexValueFormatFlags=[]; AFlags: TOperandFlags=[]); procedure AddStdOperands(AIndex: Byte); procedure AddStdReg(AIndex: Byte); procedure AddStdReg(AIndex: Byte; AType: TRegisterType); procedure Check32; procedure Check64; procedure CheckLock; procedure CheckRepeat; procedure CheckRepeatX; procedure CheckSIMD; procedure Do2ByteOpcode; procedure Do3DNow; procedure DoDisassemble; procedure DoGroup1; procedure DoGroup2; procedure DoGroup3; procedure DoGroup4; procedure DoGroup5; procedure DoGroup6; procedure DoGroup7; procedure DoGroup8; procedure DoGroup9; procedure DoGroup10; procedure DoGroup11; procedure DoGroup12; procedure DoGroup13; procedure DoGroup14; procedure DoGroup15; procedure DoGroup16; procedure DoGroupP; procedure DoX87; function AddressSize32: TAddressSize; function DecodePrefix(AOpcode, AOpcode66, AOpcodeF2, AOpcodeF3: TOpCode): TSimdOpcode; procedure Default64; procedure Force64; function Ignore64(s: String): String; function OperandSize: TOperandSize; function SizeReg32(const AReg: String): String; function SizeReg32(const AReg: String; ASize: TOperandSize): String; procedure StdCond(AIndex: Byte); function StdReg(AIndex: Byte; AType: TRegisterType; AExtReg: Boolean): String; function StdReg(AIndex: Byte): String; public procedure Disassemble(AMode: TFPDMode; var AAddress: Pointer; out AnInstruction: TInstruction); end; TX86AsmDecoder = class; { TX86AsmInstruction } TX86AsmInstruction = class(TDbgAsmInstruction) const INSTR_CODEBIN_LEN = 16; private FProcess: TDbgProcess; FAddress: TDBGPtr; FCodeBin: array[0..INSTR_CODEBIN_LEN-1] of byte; FInstruction: TInstruction; FInstrLen: Integer; FFlags: set of (diCodeRead, diCodeReadError, diDisAss); protected procedure ReadCode; inline; procedure Disassemble; inline; public constructor Create(AProcess: TDbgProcess); procedure SetAddress(AnAddress: TDBGPtr); function IsCallInstruction: boolean; override; function IsReturnInstruction: boolean; override; function IsLeaveStackFrame: boolean; override; //function ModifiesBasePointer: boolean; override; function ModifiesStackPointer: boolean; override; function IsJumpInstruction(IncludeConditional: Boolean = True; IncludeUncoditional: Boolean = True): boolean; override; function InstructionLength: Integer; override; function X86OpCode: TOpCode; property X86Instruction: TInstruction read FInstruction; // only valid after call to X86OpCode end; { TX86AsmDecoder } TX86AsmDecoder = class(TDbgAsmDecoder) private const MAX_CODEBIN_LEN = 50; //FMaxInstructionSize = 16; //FMinInstructionSize = 1; private FProcess: TDbgProcess; FLastErrWasMem: Boolean; FCodeBin: array[0..MAX_CODEBIN_LEN-1] of byte; FLastInstr: TX86AsmInstruction; protected function GetLastErrorWasMemReadErr: Boolean; override; function GetMaxInstrSize: integer; override; function GetMinInstrSize: integer; override; function GetCanReverseDisassemble: boolean; override; function ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal): Boolean; inline; public constructor Create(AProcess: TDbgProcess); override; destructor Destroy; override; procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); override; function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; override; function GetFunctionFrameInfo(AnAddress: TDBGPtr; out AnIsOutsideFrame: Boolean): Boolean; override; end; implementation var DBG_WARNINGS: PLazLoggerLogGroup; const ADDRESS_BYTES: array[TAddressSize] of Byte = (2, 4, 8); OPERAND_BYTES: array[TOperandSize] of Byte = (1, 2, 4, 8, 6, 10, 16); OPERAND_REG: array[os8..os64] of TRegisterType = (reg8, reg16, reg32, reg64); STD_REGS = [reg8..reg64]; ADDRESS_REG: array[TAddressSize] of TRegisterType = (reg16, reg32, reg64); // reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug, regX87 REGISTER_SIZE: array[TFPDMode, reg8..High(TRegisterType)] of TOperandSize = ( { dm32 } (os8, os16, os32, os64, os64, os128, os16, os32, os32, os80), { dm64 } (os8, os16, os32, os64, os64, os128, os16, os64, os64, os80) ); OPCODE_NAME: array [TOpCode] of String = ( '???', // OPX_InternalUnknown '???', '**x87**', '-x87-', '!x87!', '-3dnow-', '**group1a**', '!group1!', '!group2!', '!group3!', '**group4**', '!group4!', '**group5**', '!group5!', '**group6**', '!group6!', '**group7**', '!group7!', '**group8**', '!group8!', '**group9**', '!group9!', '**group10**', '!group10!', '**group11**', '!group11!', '**group12**', '!group12!', '**group13**', '!group13!', '**group14**', '!group14!', '**group15**', '!group15!', '**group16**', '!group16!', '**groupp**', '!groupp!', '**sysenter**', '**sysexit**', 'fadd', 'fmul', 'fcom', 'fcomp', 'fsub', 'fsubr', 'fdiv', 'fdivr', 'fld', 'fxch', 'fst', 'fstp', 'fldenv', 'fldcw', 'fnstenv', 'fnstcw', 'fchs', 'fabs', 'ftst', 'fxam', 'fld1', 'fldl2t', 'fldl2e', 'fldpi', 'fldlg2', 'fldln2', 'fldz', 'f2xm1', 'fyl2x', 'fptan', 'fpatan', 'fxtract', 'fprem1', 'fdecstp', 'fincstp', 'fprem', 'fyl2xp1', 'fsqrt', 'fsincos', 'frndint', 'fscale', 'fsin', 'fcos', 'nop', 'fiadd', 'fimull', 'ficom', 'ficomp', 'fisub', 'fisubr', 'fidiv', 'fidivr', 'fcmovb', 'fcmove', 'fcmovbe', 'fcmovu', 'fucompp', 'fild', 'fisttp', 'fist', 'fistp', 'fcmovnb', 'fcmovne', 'fcmovnbe', 'fcmovnu', 'fucomi', 'fcomi', 'fnclex', 'fninit', 'frstor', 'fnsave', 'fnstsw', 'ffree', 'fucomp', 'faddp', 'fmullp', 'fsubrp', 'fsubp', 'fdivrp', 'fdivp', 'fbld', 'fbstp', 'fcompp', 'fucomip', 'fcomip', 'pi2fw', 'pi2fd', 'pf2iw', 'pf2id', 'pfnacc', 'pfpnacc', 'pfcmpge', 'pfmin', 'pfrcp', 'pfrsqrt', 'pfsub', 'pfadd', 'pgcmpgt', 'pfmax', 'pfrcpit1', 'pfrsqit1', 'pfsubr', 'pfacc', 'pfcmpeq', 'pfmul', 'pfrcpit2', 'pmulhrw', 'pswapd', 'pavgusb', 'add', 'or', 'adc', 'sbb', 'and', 'sub', 'xor', 'cmp','pop', 'rol', 'ror', 'rcl', 'rcr', 'shl', 'shr', 'sal', 'sar', 'test', 'not', 'neg', 'mul', 'imul', 'div', 'idiv', 'inc', 'dec', 'call', 'jmp', 'push', 'sldt', 'str', 'lldt', 'ltr', 'verr', 'verw', 'vmrun', 'vmmcall', 'vmload', 'vmsave', 'stgi', 'clgi', 'skinit', 'invlpga', 'sgdt', 'sidt', 'lgdt', 'lidt', 'smsw', 'lmsw', 'swapgs', 'rdtscp', 'invlpg', 'bts', 'btr', 'btc', 'bt', 'cmpxchg16b', 'cmpxchg8b', 'mov', 'psrlw', 'psraw', 'psllw', 'psrld', 'psrad', 'pslld', 'psrlq', 'psrldq', 'psllq', 'fxsave', 'fxrstor', 'ldmxcsr', 'stmxcsr', 'lfence', 'mfence', 'clflush', 'prefetch exclusive', 'prefetch modified', '--prefetch--', 'punpcklbw', 'punpcklwd', 'punpcklqd', 'packsswb', 'pcmpgtb', 'pcmpgtw', 'pcmpgtd', 'packuswb', 'punpkhbw', 'punpkhwd', 'punpkhdq', 'packssdw', 'punpcklqdq', 'punpckhqdq', 'paddq', 'pmullw', 'psubusb', 'psubusw', 'pminub', 'pand', 'paddusb', 'paddusw', 'pmaxub', 'pandn', 'pavgb', 'pavgw', 'pmulhuw', 'pmulhw', 'psubsb', 'psubsw', 'pminsw', 'por', 'paddsb', 'paddsw', 'pmaxsw', 'pxor', 'pmuludq', 'pmaddwd', 'psadbw', 'psubb', 'psubw', 'psubd', 'psubq', 'paddb', 'paddw', 'paddd', 'lar', 'lsl', 'syscall', 'clts', 'sysret', 'invd', 'wbinvd', 'ud2', 'femms', 'movups', 'movss', 'movupd', 'movsd', 'movhlps', 'movsldup', 'movlpd', 'movddup', 'movlps', 'unpcklps', 'unpcklpd', 'unpckhps', 'unpckhpd', 'movlhps', 'movshdup', 'movhpd', 'movhps', 'movaps', 'movapd', 'cvtpi2ps', 'cvtsi2ss', 'cvtpi2pd', 'cvtsi2sd', 'movntps', 'movntpd', 'cvttps2pi', 'cvttss2si', 'cvttpd2pi', 'cvttsd2si', 'cvtps2pi', 'cvtss2si', 'cvtpd2pi', 'cvtsd2si', 'ucomiss', 'ucomissd', 'comiss', 'comissd', 'wrmsr', 'rdtsc', 'rdmsr', 'rdpmc', 'cmov', 'movmskps', 'movmskpd', 'sqrtps', 'sqrtss', 'sqrtpd', 'sqrtsd', 'addps', 'addss', 'addpd', 'addsd', 'mulps', 'mulss', 'mulpd', 'mulsd', 'subps', 'subss', 'subpd', 'subsd', 'minps', 'minss', 'minpd', 'minsd', 'divps', 'divss', 'divpd', 'divsd', 'maxps', 'maxss', 'maxpd', 'maxsd', 'rsqrtps', 'rsqrtss', 'rcpps', 'rcpss', 'andps', 'andpd', 'andnps', 'andnpd', 'orps', 'orpd', 'xorps', 'xorpd', 'cvtps2pd', 'cvtss2sd', 'cvtpd2ps', 'cvtsd2ss', 'cvtdq2ps', 'cvttps2dq', 'cvtps2dq', 'movd', 'movq', 'movdqu', 'movdqa', 'pshufw', 'pshufhw', 'pshufd', 'pshuflw', 'pcmpeqb', 'pcmpeqw', 'pcmpeqd', 'emms', 'haddpd', 'haddps', 'hsubpd', 'hsubps', 'j', // cond jump + suffix 'set', 'cpuid', 'shld', 'rsm', 'shrd', 'cmpxchg', 'lss', 'lfs', 'lgs', 'movzx', 'bsf', 'bsr', 'movsx', 'xadd', 'cmpps', 'cmpss', 'cmppd', 'cmpsd', 'movnti', 'pinsrw', 'pextrw', 'shufps', 'shufpd', 'bswp', 'addsubpd', 'addsubps', 'movq2dq', 'movdq2q', 'pmovmskb', 'cvtdq2pd', 'cvttpd2dq', 'cvtpd2dq', 'movntq', 'movntdqu', 'lddqu', 'maskmovq', 'maskmovdqu', 'daa', 'das', 'aaa', 'aas', 'pusha', 'pushad', 'popa', 'popad', 'bound', 'movsxd', 'arpl', 'insb', 'insw', 'insd', 'outsb', 'outsw', 'outsd', 'xchg', 'lea', 'cdqe', 'cwde', 'cbw', 'cqo', 'cqd', 'cwd', 'wait/fwait', 'pushfq', 'pushfd', 'pushf', 'popfq', 'popfd', 'popf', 'sahf', 'lahf', 'movsb', 'movsq', 'movsw', 'cmpsb', 'cmpsq', 'cmpsw', 'stosb', 'stosq', 'stosd', 'stosw', 'lodsb', 'lodsq', 'lodsd', 'lodsw', 'scasb', 'scasq', 'scasd', 'scasw', 'ret', 'les', 'lds', 'enter', 'leave', 'retf', 'int3', 'int', 'int0', 'iretq', 'iretd', 'iret', 'aam', 'aad', 'salc', 'xlat', 'loopne', 'loope', 'loop', 'jrcxz', 'in', 'out', 'int1', 'hlt', 'cmc', 'clc', 'stc', 'cli', 'sti', 'cld', 'std' ); OPCODE_SUFFIX_NAME: array [TOpCodeSuffix] of String = ( '', 'o', 'no', 'b', 'nb', 'z', 'nz', 'be', 'nbe', 's', 'ns', 'p', 'np', 'l', 'nl', 'le', 'nle' ); { TX86Disassembler } procedure TX86Disassembler.Check32; begin // only valid in 32-bit ProcessMode if (ProcessMode = dm64) then Include(Instruction^.Flags, ifOnly32); end; procedure TX86Disassembler.Check64; begin // only valid in 64-bit ProcessMode if (ProcessMode = dm64) then Include(Instruction^.Flags, ifOnly64); end; function TX86Disassembler.Ignore64(s: String): String; begin // ignored in 64-bit ProcessMode if (ProcessMode = dm64) then Result := '('+s+')' else Result := s; end; procedure TX86Disassembler.Default64; begin if ProcessMode = dm64 then Include(Flags, oprDefault64); end; procedure TX86Disassembler.Force64; begin if ProcessMode = dm64 then Include(Flags, oprForce64); end; procedure TX86Disassembler.CheckLock; function CheckMem: boolean; var n: Byte; begin Result := True; for n := 1 to OperIdx do if ofMemory in Instruction^.Operand[n].Flags then Exit; Result := False; end; begin if (preLock in Flags) and CheckMem then begin Exclude(Flags, preLock); Include(Instruction^.Flags, ifPrefixLock); end; end; procedure TX86Disassembler.CheckRepeat; begin if preF3 in Flags then begin Exclude(Flags, preF3); Include(Instruction^.Flags, ifPrefixRep); end; end; procedure TX86Disassembler.CheckRepeatX; begin if preF3 in Flags then begin Exclude(Flags, preF3); Include(Instruction^.Flags, ifPrefixRepE); Exit; end; if preF2 in Flags then begin Exclude(Flags, preF2); Include(Instruction^.Flags, ifPrefixRepNe); Exit; end; end; procedure TX86Disassembler.CheckSIMD; var check: TFlags; begin check := Flags * [pre66, preF3, preF2]; if check = [] then SimdOpcode := soNone else if check - [preF3] = [] then SimdOpcode := soF3 else if check - [preF2] = [] then SimdOpcode := soF2 else if check - [pre66] = [] then SimdOpcode := so66 else SimdOpcode := soInvalid; end; function TX86Disassembler.DecodePrefix(AOpcode, AOpcode66, AOpcodeF2, AOpcodeF3: TOpCode): TSimdOpcode; begin CheckSIMD; case SimdOpcode of soNone: Instruction^.Opcode := AOpcode; so66: Instruction^.Opcode := AOpcode66; soF2: Instruction^.Opcode := AOpcodeF2; soF3: Instruction^.Opcode := AOpcodeF3; else Instruction^.Opcode := OPX_Invalid; end; if Instruction^.Opcode = OPX_Invalid then begin Result := soInvalid; end else begin Flags := Flags - [pre66, preF2, preF3]; Result := SimdOpcode; end; end; function TX86Disassembler.AddressSize32: TAddressSize; begin // effective address size for default 32 AnInstruction.operand size if (ProcessMode = dm64) then begin if preAdr in Flags then Result := as32 else Result := as64; end else begin if preAdr in Flags then Result := as16 else Result := as32; end; end; function TX86Disassembler.OperandSize: TOperandSize; begin // effective AnInstruction.operand size // Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 1: // 3.6 OPERAND-SIZE AND ADDRESS-SIZE ATTRIBUTES // // Table 3-3 D-flag = 1 for 32 bit processes -> // default 32, prefix 16 // // Table 3-4 // REX.W 64, default 32, prefix 16 (REX.W overrules prefix) // // So for both dm32 and dm64 the default size is 32 unless overridden by flags // A.3 ONE, TWO, AND THREE-BYTE Instruction^.Opcode MAPS // Some instructions default or force to 64bit in dm64 if [oprForce64, rexW] * Flags <> [] then begin Result := os64; end else begin if pre66 in Flags then Result := os16 else if oprDefault64 in Flags then Result := os64 else Result := os32; end; end; procedure TX86Disassembler.AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []; AByteCount2: Byte = 0); begin Inc(OperIdx); if OperIdx > High(Instruction^.Operand) then begin Debugln(DBG_WARNINGS, 'AddOperand: Only %d operands supported, got %d', [High(Instruction^.Operand), OperIdx]); Exit; end; Instruction^.Operand[OperIdx].Size := ASize; Instruction^.Operand[OperIdx].ByteCount := AByteCount; Instruction^.Operand[OperIdx].ByteCount2 := AByteCount2; Instruction^.Operand[OperIdx].FormatFlags := AFormatFlags; Instruction^.Operand[OperIdx].Value := AValue; Instruction^.Operand[OperIdx].Flags := AFlags; end; procedure TX86Disassembler.AddOperand(const AValue: String; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []); begin AddOperand(AValue, OperandSize, AByteCount, AFormatFlags, AFlags); end; function TX86Disassembler.SizeReg32(const AReg: String; ASize: TOperandSize): String; begin // prefix a reg for default 32 AnInstruction.operand size case ASize of os64: Result := 'r' + AReg; os32: Result := 'e' + AReg; else Result := AReg; end; end; function TX86Disassembler.SizeReg32(const AReg: String): String; begin Result := SizeReg32(AReg, OperandSize); end; procedure TX86Disassembler.StdCond(AIndex: Byte); const COND: array[0..$F] of TOpCodeSuffix = ( OPSx_o, OPSx_no, OPSx_b, OPSx_nb, OPSx_z, OPSx_nz, OPSx_be, OPSx_nbe, OPSx_s, OPSx_ns, OPSx_p, OPSx_np, OPSx_l, OPSx_nl, OPSx_le, OPSx_nle ); begin Instruction^.OpCodeSuffix := COND[AIndex and $F]; end; function TX86Disassembler.StdReg(AIndex: Byte; AType: TRegisterType; AExtReg: Boolean): String; const REGS: array[0..7] of string = ('ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di'); REG8_: array[0..7] of String = ('al', 'cl', 'dl', 'bl', 'ah', 'ch', 'dh', 'bh'); REG8r: array[0..7] of String = ('al', 'cl', 'dl', 'bl', 'spl', 'bpl', 'sil', 'dil'); SREG: array[0..7] of String = ('es', 'cs', 'ss', 'ds', 'fs', 'gs', '**', '**'); POSTFIX: array[reg16..reg64] of String = ('w', 'd', ''); OSMAP: array[reg8..reg64] of TOperandSize = (os8, os16, os32, os64); begin AIndex := AIndex and $7; case AType of reg8: begin if AExtReg then begin Result := Format('r%db', [8 + AIndex]); end else begin if flagRex in Flags then Result := REG8r[AIndex] else Result := REG8_[AIndex]; end; end; reg16..reg64: begin if AExtReg then Result := Format('r%d', [8 + AIndex]) + POSTFIX[AType] else Result := SizeReg32(REGS[AIndex], OSMAP[AType]); end; regX87: begin Result := Format('st(%d)', [AIndex]); end; regMmx: begin Result := Format('mmx%d', [AIndex]); end; regXmm: begin if AExtReg then Inc(AIndex, 8); Result := Format('xmm%d', [AIndex]); end; regSegment: begin Result := SREG[AIndex]; end; regControl: begin if AExtReg then Inc(AIndex, 8); Result := Format('cr%d', [AIndex]); end; regDebug: begin if AExtReg then Inc(AIndex, 8); Result := Format('dr%d', [AIndex]); end; end; end; function TX86Disassembler.StdReg(AIndex: Byte): String; begin Result := StdReg(AIndex, OPERAND_REG[OperandSize], rexB in Flags); end; procedure TX86Disassembler.AddStdReg(AIndex: Byte; AType: TRegisterType); begin AddOperand(StdReg(AIndex, AType, rexB in Flags), REGISTER_SIZE[ProcessMode, AType]); end; procedure TX86Disassembler.AddStdReg(AIndex: Byte); begin AddOperand(StdReg(AIndex)); end; procedure TX86Disassembler.AddModReg(AType: TRegisterType; ASize: TOperandSize); begin Include(Flags, flagModRM); AddOperand(StdReg(Code[ModRMIdx] shr 3, AType, rexR in Flags), ASize); end; procedure TX86Disassembler.AddModReg(AType: TRegisterType); begin Include(Flags, flagModRM); AddOperand(StdReg(Code[ModRMIdx] shr 3, AType, rexR in Flags), REGISTER_SIZE[ProcessMode, AType]); end; procedure TX86Disassembler.AddModReg; begin Include(Flags, flagModRM); AddOperand(StdReg(Code[ModRMIdx] shr 3, OPERAND_REG[OperandSize], rexR in Flags)); end; procedure TX86Disassembler.AddModRM(AReqTypes: TModRMTypes; ASize: TOperandSize; AType: TRegisterType); var Mode, Rm: Byte; procedure Mem16; const REGS16: array[0..7] of string = ('bx+si', 'bx+di', 'bp+si', 'bp+di', 'si', 'di', 'bp', 'bx'); begin case Mode of 0: begin if rm = 6 // disp16 -> exception to the regs then AddOperand('%s', ASize, 2, [hvfSigned, hvfIncludeHexchar], [ofMemory]) else AddOperand(REGS16[rm], ASize, 0, [], [ofMemory]); end; 1: AddOperand(REGS16[rm] + '%s', ASize, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]); 2: AddOperand(REGS16[rm] + '%s', ASize, 2, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]); end; end; var AddrSize: TAddressSize; Sib: record Scale, Index, Base: Byte; end; Oper: record Size: Byte; Flags: THexValueFormatFlags; Value: String; end; begin Include(Flags, flagModRM); Mode := Code[ModRMIdx] shr 6; Rm := Code[ModRMIdx] and $7; // Check for reg (ProcessMode = 3) first; if Mode = 3 then begin if modReg in AReqTypes then AddStdReg(rm, AType) else AddOperand('**'); Exit; end; // Check if mem is allowed if not (modMem in AReqTypes) then begin AddOperand('**', 0, [], [ofMemory]); Exit; end; Oper.Size := 0; Oper.Flags := []; Oper.Value := ''; // Here only mem access AddrSize := AddressSize32; if AddrSize = as16 then begin Mem16; Exit; end; if rm = 4 then begin // sib folows Include(Flags, flagSib); sib.Scale := Code[ModRMIdx+1] shr 6; sib.Index := (Code[ModRMIdx+1] shr 3) and $7; sib.Base := Code[ModRMIdx+1] and $7; // base if (Mode = 0) and (sib.Base = 5) then begin // disp32 Oper.Value := '%s'; Oper.Size := 4; if (sib.Index <> 4) or (rexX in Flags) then Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar] // [reg + base] else Oper.Flags := [hvfSigned, hvfIncludeHexchar]; // [base] end else begin Oper.Value := StdReg(sib.Base, ADDRESS_REG[AddrSize], rexB in Flags); if (sib.Index <> 4) or (rexX in Flags) then Oper.Value := '+' + Oper.Value; // [reg + base] end; // reg if (rexX in Flags) or (sib.Index <> 4) then begin if sib.Scale > 0 then Oper.Value := Format('*%u', [1 shl sib.Scale]) + Oper.Value; // get index Oper.Value := StdReg(sib.Index, ADDRESS_REG[AddrSize], rexX in Flags) + Oper.Value end; end else begin // no sib Oper.Value := StdReg(rm, ADDRESS_REG[AddrSize], rexB in Flags); end; case Mode of 0: begin // exceptions to std encoding if rm = 5 then begin // disp32 if AddrSize = as64 then begin Oper.Value := 'rip%s'; Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]; end else begin Oper.Value := '%s'; Oper.Flags := [hvfSigned, hvfIncludeHexchar]; end; Oper.Size := 4; end; end; 1: begin Oper.Value := Oper.Value + '%s'; Oper.Size := 1; Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]; end; 2: begin Oper.Value := Oper.Value + '%s'; Oper.Size := 4; Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]; end; end; AddOperand(Oper.Value, ASize, Oper.Size, Oper.Flags, [ofMemory]); end; procedure TX86Disassembler.AddAp; begin if OperandSize = os16 //XXXX:XXXX then AddOperand('$%1:s:%0:s', os32, 2, [], [], 2) else AddOperand('$%1:s:%0:s', os48, 4, [], [], 2) end; procedure TX86Disassembler.AddCd_q; begin AddModReg(regControl); end; procedure TX86Disassembler.AddDd_q; begin AddModReg(regDebug); end; procedure TX86Disassembler.AddEb; begin AddModRM([modReg, modMem], os8, reg8); end; procedure TX86Disassembler.AddEd; begin AddModRM([modReg, modMem], os32, reg32); end; procedure TX86Disassembler.AddEd_q; begin if flagRex in Flags then AddModRM([modReg, modMem], os64, reg64) else AddModRM([modReg, modMem], os32, reg32); end; procedure TX86Disassembler.AddEv; begin AddModRM([modReg, modMem], OperandSize, OPERAND_REG[OperandSize]); end; procedure TX86Disassembler.AddEw; begin AddModRM([modReg, modMem], os16, reg16); end; procedure TX86Disassembler.AddFv; begin case OperandSize of os64: AddOperand('rflags'); os32: AddOperand('eflags'); else AddOperand('flags'); end; end; procedure TX86Disassembler.AddGb; begin AddModReg(reg8); end; procedure TX86Disassembler.AddGd; begin AddModReg(reg32); end; procedure TX86Disassembler.AddGd_q; begin if flagRex in Flags then AddModReg(reg64) else AddModReg(reg32); end; procedure TX86Disassembler.AddGv; begin AddModReg; end; procedure TX86Disassembler.AddGw; begin AddModReg(reg16); end; procedure TX86Disassembler.AddGz; begin if OperandSize = os16 then AddModReg(reg16) else AddModReg(reg32); end; procedure TX86Disassembler.AddIb; begin AddOperand('%s', os8, 1, [hvfIncludeHexchar]); end; procedure TX86Disassembler.AddIv; begin AddOperand('%s', OPERAND_BYTES[OperandSize], [hvfIncludeHexchar]); end; procedure TX86Disassembler.AddIw; begin AddOperand('%s', os16, 2, [hvfIncludeHexchar]); end; procedure TX86Disassembler.AddIz; begin if OperandSize = os16 then AddOperand('%s', os16, 2, [hvfIncludeHexchar]) else AddOperand('%s', os32, 4, [hvfIncludeHexchar]); end; procedure TX86Disassembler.AddJb; begin AddOperand('%s', os8, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]); end; procedure TX86Disassembler.AddJz; begin if OperandSize = os16 then AddOperand('%s', os16, 2, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]) else AddOperand('%s', os32, 4, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]); end; procedure TX86Disassembler.AddM; begin AddModRM([modMem], OperandSize, reg0 {do not care}); end; procedure TX86Disassembler.AddMa; begin AddModRM([modMem], OperandSize, reg0 {do not care}); end; procedure TX86Disassembler.AddMb; begin AddModRM([modMem], os8, reg0 {do not care}); end; procedure TX86Disassembler.AddMd; begin AddModRM([modMem], os32, reg0 {do not care}); end; procedure TX86Disassembler.AddMd_q; begin if flagRex in Flags then AddModRM([modMem], os64, reg0 {do not care}) else AddModRM([modMem], os32, reg0 {do not care}); end; procedure TX86Disassembler.AddMdq; begin AddModRM([modMem], os128, reg0 {do not care}) end; procedure TX86Disassembler.AddMp; begin if OperandSize = os16 //XXXX:XXXX then AddModRM([modMem], os32, reg0 {do not care}) else AddModRM([modMem], os48, reg0 {do not care}); end; procedure TX86Disassembler.AddMq; begin AddModRM([modMem], os64, reg0 {do not care}); end; procedure TX86Disassembler.AddMs; begin if (ProcessMode = dm64) then AddModRM([modMem], os80, reg0 {do not care}) else AddModRM([modMem], os48, reg0 {do not care}); end; procedure TX86Disassembler.AddMw_Rv; begin if Code[ModRMIdx] shr 6 = 3 // ProcessMode = 3 -> reg then AddModRM([modReg], OperandSize, OPERAND_REG[OperandSize]) else AddModRM([modMem], os16, reg0 {do not care}); end; procedure TX86Disassembler.AddOb; begin AddOperand('%s', os8, ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], [ofMemory]) end; procedure TX86Disassembler.AddOv; begin AddOperand('%s', ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], [ofMemory]) end; procedure TX86Disassembler.AddPd_q; begin if flagRex in Flags then AddModReg(regMmx, os64) else AddModReg(regMmx, os32); end; procedure TX86Disassembler.AddPq; begin AddModReg(regMmx); end; procedure TX86Disassembler.AddPRq; begin AddModRM([modReg], os64, regMmx); end; procedure TX86Disassembler.AddQd; begin AddModRM([modReg, modMem], os32, regMmx); end; procedure TX86Disassembler.AddQq; begin AddModRM([modReg, modMem], os64, regMmx); end; procedure TX86Disassembler.AddRd_q; begin if (ProcessMode = dm64) then AddModRM([modReg], os64, reg64) else AddModRM([modReg], os32, reg32); end; procedure TX86Disassembler.AddSw; begin AddModReg(regSegment); end; procedure TX86Disassembler.AddVd_q; begin if flagRex in Flags then AddModReg(regXmm, os64) else AddModReg(regXmm, os32); end; procedure TX86Disassembler.AddVdq; begin AddModReg(regXmm, os128); end; procedure TX86Disassembler.AddVdq_sd; begin AddModReg(regXmm, os64); // only lower 64 bit end; procedure TX86Disassembler.AddVdq_ss; begin AddModReg(regXmm, os32); // only lower 32 bit end; procedure TX86Disassembler.AddVpd; begin AddModReg(regXmm, os128); end; procedure TX86Disassembler.AddVps; begin AddModReg(regXmm, os128); end; procedure TX86Disassembler.AddVq; begin AddModReg(regXmm, os64); end; procedure TX86Disassembler.AddVsd; begin AddModReg(regXmm, os64); end; procedure TX86Disassembler.AddVss; begin AddModReg(regXmm, os32); end; procedure TX86Disassembler.AddVRdq; begin AddModRM([modReg], os128, regXmm); end; procedure TX86Disassembler.AddVRpd; begin AddModRM([modReg], os128, regXmm); end; procedure TX86Disassembler.AddVRps; begin AddModRM([modReg], os128, regXmm); end; procedure TX86Disassembler.AddVRq; begin AddModRM([modReg], os64, regXmm); end; procedure TX86Disassembler.AddWdq; begin AddModRM([modReg, modMem], os128, regXmm); end; procedure TX86Disassembler.AddWpd; begin AddModRM([modReg, modMem], os128, regXmm); end; procedure TX86Disassembler.AddWps; begin AddModRM([modReg, modMem], os128, regXmm); end; procedure TX86Disassembler.AddWq; begin AddModRM([modReg, modMem], os64, regXmm); end; procedure TX86Disassembler.AddWsd; begin AddModRM([modReg, modMem], os64, regXmm); end; procedure TX86Disassembler.AddWss; begin AddModRM([modReg, modMem], os32, regXmm); end; {$ifdef verbose_string_instructions} procedure TX86Disassembler.AddXb; begin AddOperand('Xb'); end; procedure TX86Disassembler.AddXv; begin AddOperand('Xv'); end; procedure TX86Disassembler.AddXz; begin AddOperand('Xz'); end; procedure TX86Disassembler.AddYb; begin AddOperand('Yb'); end; procedure TX86Disassembler.AddYv; begin AddOperand('Yv'); end; procedure TX86Disassembler.AddYz; begin AddOperand('Yz'); end; {$endif} procedure TX86Disassembler.AddStdOperands(AIndex: Byte); begin case AIndex and $7 of 0: begin AddEb; AddGb; end; 1: begin AddEv; AddGv; end; 2: begin AddGb; AddEb; end; 3: begin AddGv; AddEv; end; 4: begin AddOperand('al', os8); AddIb; end; 5: begin AddOperand(SizeReg32('ax')); AddIz; end; else AddOperand('!!'); end; end; procedure TX86Disassembler.DoX87; var Index: Byte; ModRM: Byte; procedure AddMem14_28Env; begin AddModRM([modMem], OperandSize, reg0 {do not care}); end; procedure AddMem98_108Env; begin AddModRM([modMem], OperandSize, reg0 {do not care}); end; procedure AddMem16; begin AddModRM([modMem], os16, reg0 {do not care}); end; procedure AddMem32; begin AddModRM([modMem], os32, reg0 {do not care}); end; procedure AddMem64; begin AddModRM([modMem], os64, reg0 {do not care}); end; procedure AddMem80; begin AddModRM([modMem], os80, reg0 {do not care}); end; procedure AddReg0; begin AddOperand('st(0)', os80); end; procedure AddRegN; begin AddOperand(Format('st(%u)', [Code[ModRMIdx] and $7]), os80); end; procedure DoD8; const OPC: array[0..7] of TOpCode = (OPfadd, OPfmul, OPfcom, OPfcomp, OPfsub, OPfsubr, OPfdiv, OPfdivr); begin Instruction^.Opcode := OPC[Index]; case ModRM of $00..$BF: AddMem32 else AddReg0; AddRegN; end; end; procedure DoD9; const OPC: array[0..7] of TOpCode = (OPfld, OPfxch, OPfst, OPfstp, OPfldenv, OPfldcw, OPfnstenv, OPfnstcw); OPCx: array[0..$1F] of TOpCode = ( OPfchs, OPfabs, OPX_InvalidX87, OPX_InvalidX87, OPftst, OPfxam, OPX_InvalidX87, OPX_InvalidX87, OPfld1, OPfldl2t, OPfldl2e, OPfldpi, OPfldlg2, OPfldln2, OPfldz, OPX_InvalidX87, OPf2xm1, OPfyl2x, OPfptan, OPfpatan, OPfxtract, OPfprem1, OPfdecstp, OPfincstp, OPfprem, OPfyl2xp1, OPfsqrt, OPfsincos, OPfrndint, OPfscale, OPfsin, OPfcos ); begin case ModRM of $00..$BF: begin Instruction^.Opcode := OPC[Index]; case Index of 0, 2, 3: AddMem32; 1: Instruction^.Opcode := OPX_InvalidX87; 4, 6 : AddMem14_28Env; 5, 7: AddMem16; end; end; $C0..$CF: begin Instruction^.Opcode := OPC[Index]; AddReg0; AddRegN; end; $D0: begin Instruction^.Opcode := OPnop; end; $D8..$DF: begin Instruction^.Opcode := OPX_ReservedX87; end; $E0..$E1, $E4..$E5, $E8..$FF: begin Instruction^.Opcode := OPCx[ModRM and $1F]; end; else Instruction^.Opcode := OPX_InvalidX87; end; end; procedure DoDA; const OPC: array[0..7] of TOpCode = (OPfiadd, OPfimull, OPficom, OPficomp, OPfisub, OPfisubr, OPfidiv, OPfidivr); OPCx: array[0..3] of TOpCode = (OPfcmovb, OPfcmove, OPfcmovbe, OPfcmovu); begin case ModRM of $00..$BF: begin Instruction^.Opcode := OPC[Index]; AddMem32; end; $C0..$DF: begin Instruction^.Opcode := OPCx[Index]; AddReg0; AddRegN; end; $E9: begin Instruction^.Opcode := OPfucompp; end; else Instruction^.Opcode := OPX_InvalidX87; end; end; procedure DoDB; const OPC: array[0..7] of TOpCode = (OPfild, OPfisttp, OPfist, OPfistp, OPX_InvalidX87, OPfld, OPX_InvalidX87, OPfstp); OPCx: array[0..7] of TOpCode = (OPfcmovnb, OPfcmovne, OPfcmovnbe, OPfcmovnu, OPX_InvalidX87, OPfucomi, OPfcomi, OPX_InvalidX87); begin case ModRM of $00..$BF: begin case Index of 0..3: begin Instruction^.Opcode := OPC[Index]; AddMem32; end; 5, 7: begin Instruction^.Opcode := OPC[Index]; AddMem80; end; else Instruction^.Opcode := OPX_InvalidX87; end; end; $C0..$DF, $E8..$F7: begin Instruction^.Opcode := OPCx[Index]; AddReg0; AddRegN; end; $E0..$E1: begin Instruction^.Opcode := OPX_ReservedX87; end; $E2: begin Instruction^.Opcode := OPfnclex; end; $E3: begin Instruction^.Opcode := OPfninit; end; $E4: begin Instruction^.Opcode := OPX_ReservedX87; end; else Instruction^.Opcode := OPX_InvalidX87; end; end; procedure DoDC; const OPC: array[0..7] of TOpCode = (OPfadd, OPfmul, OPfcom, OPfcomp, OPfsub, OPfsubr, OPfdiv, OPfdivr); OPCx: array[0..7] of TOpCode = (OPfadd, OPfmul, OPX_InvalidX87, OPX_InvalidX87, OPfsubr, OPfsub, OPfdivr, OPfdiv); begin case ModRM of $00..$BF: begin Instruction^.Opcode := OPC[Index]; AddMem64; end; $C0..$CF, $E0..$FF: begin Instruction^.Opcode := OPCx[Index]; AddRegN; AddReg0; end; else Instruction^.Opcode := OPX_ReservedX87; end; end; procedure DoDD; const OPC: array[0..7] of TOpCode = (OPfld, OPfisttp, OPfst, OPfstp, OPfrstor, OPX_InvalidX87, OPfnsave, OPfnstsw); OPCx: array[0..7] of TOpCode = (OPffree, OPX_InvalidX87, OPfst, OPfstp, OPX_InvalidX87, OPfucomp, OPX_InvalidX87, OPX_InvalidX87); begin case ModRM of $00..$BF: begin case Index of 0..3: begin Instruction^.Opcode := OPC[Index]; AddMem64; end; 4, 6: begin Instruction^.Opcode := OPC[Index]; AddMem98_108Env; end; 5: Instruction^.Opcode := OPX_InvalidX87; 7: begin Instruction^.Opcode := OPC[Index]; AddMem16; end; end; end; $C0..$C7, $D0..$DF, $E8..$EF: begin Instruction^.Opcode := OPCx[Index]; AddRegN; end; $E0..$E7: begin Instruction^.Opcode := OPCx[Index]; AddRegN; AddReg0; end; $C8..$CF: Instruction^.Opcode := OPX_ReservedX87; else Instruction^.Opcode := OPX_InvalidX87; end; end; procedure DoDE; const OPC: array[0..7] of TOpCode = (OPfiadd, OPfimull, OPficom, OPficomp, OPfisub, OPfisubr, OPfidiv, OPfidivr); OPCx: array[0..7] of TOpCode = (OPfaddp, OPfmullp, OPX_InvalidX87, OPX_InvalidX87, OPfsubrp, OPfsubp, OPfdivrp, OPfdivp); begin case ModRM of $00..$BF: begin Instruction^.Opcode := OPC[Index]; AddMem16; end; $C0..$CF, $E0..$FF: begin Instruction^.Opcode := OPCx[Index]; AddRegN; AddReg0; end; $D9: begin Instruction^.Opcode := OPfcompp; end; $D0..$D7: Instruction^.Opcode := OPX_ReservedX87; else Instruction^.Opcode := OPX_InvalidX87; end; end; procedure DoDF; const OPC: array[0..7] of TOpCode = (OPfild, OPfisttp, OPfist, OPfistp, OPfbld, OPfild, OPfbstp, OPfistp); begin case ModRM of $00..$BF: begin case Index of 0..3: begin Instruction^.Opcode := OPC[Index]; AddMem16; end; 4, 6: begin Instruction^.Opcode := OPC[Index]; AddMem80; end; 5, 7: begin Instruction^.Opcode := OPC[Index]; AddMem64; end; end; end; $E0: begin Instruction^.Opcode := OPfnstsw; AddOperand('ax', os16); end; $E8..$EF: begin Instruction^.Opcode := OPfucomip; AddReg0; AddRegN; end; $F0..$F7: begin Instruction^.Opcode := OPfcomip; AddReg0; AddRegN; end; $C0..$DF: Instruction^.Opcode := OPX_ReservedX87; else Instruction^.Opcode := OPX_InvalidX87; end; end; begin Include(Flags, flagModRM); ModRM := Code[ModRMIdx]; Index := (ModRM shr 3) and $7; case Code[CodeIdx] of $D8: DoD8; $D9: DoD9; $DA: DoDA; $DB: DoDB; $DC: DoDC; $DD: DoDD; $DE: DoDE; $DF: DoDF; else Instruction^.Opcode := OPX_Not87; end; end; procedure TX86Disassembler.Do3DNow; var n, idx: Byte; begin // 0Fh 0Fh [ModRM] [SIB] [displacement] imm8_opcode // sigh, we need to get the operands first, luckely they are all te same. AddPq; AddQq; // to adjust the instruction length, add an empty AnInstruction.operand for the Instruction^.Opcode AddOperand('', 1); // calc index of imm_opcode idx := 0; if flagModRM in Flags then Inc(idx); if flagSib in Flags then Inc(idx); for n := 1 to OperIdx do begin Inc(idx, Instruction^.Operand[n].ByteCount); Inc(idx, Instruction^.Operand[n].ByteCount2); end; // now we can lookup the Instruction^.Opcode case Code[CodeIdx + idx] of $0C: Instruction^.Opcode := OPpi2fw; $0D: Instruction^.Opcode := OPpi2fd; $1C: Instruction^.Opcode := OPpf2iw; $1D: Instruction^.Opcode := OPpf2id; $8A: Instruction^.Opcode := OPpfnacc; $8E: Instruction^.Opcode := OPpfpnacc; $90: Instruction^.Opcode := OPpfcmpge; $94: Instruction^.Opcode := OPpfmin; $96: Instruction^.Opcode := OPpfrcp; $97: Instruction^.Opcode := OPpfrsqrt; $9A: Instruction^.Opcode := OPpfsub; $9E: Instruction^.Opcode := OPpfadd; $A0: Instruction^.Opcode := OPpgcmpgt; $A4: Instruction^.Opcode := OPpfmax; $A6: Instruction^.Opcode := OPpfrcpit1; $A7: Instruction^.Opcode := OPpfrsqit1; $AA: Instruction^.Opcode := OPpfsubr; $AE: Instruction^.Opcode := OPpfacc; $B0: Instruction^.Opcode := OPpfcmpeq; $B4: Instruction^.Opcode := OPpfmul; $B6: Instruction^.Opcode := OPpfrcpit2; $B7: Instruction^.Opcode := OPpmulhrw; $BB: Instruction^.Opcode := OPpswapd; $BF: Instruction^.Opcode := OPpavgusb; else Instruction^.Opcode := OPX_3dnow; end; end; procedure TX86Disassembler.DoGroup1; const OPC: array[0..7] of TOpCode = (OPadd, OPor, OPadc, OPsbb, OPand, OPsub, OPxor, OPcmp); var Index: Byte; begin Include(Flags, flagModRM); Index := (Code[ModRMIdx] shr 3) and 7; // group 1a if Code[CodeIdx] = $8F then begin if Index = 0 then begin Instruction^.Opcode := OPpop; AddEv; end else Instruction^.Opcode := OPX_group1a; Exit; end; // Group 1 Instruction^.Opcode := OPC[Index]; case Code[CodeIdx] of $80: begin AddEb; AddIb; end; $81: begin AddEv; AddIz; end; $82: begin AddEb; AddIb; Check32; end; $83: begin AddEv; AddIb; end; else Instruction^.Opcode := OPX_NotGroup1; Exit; end; if (Index <> 7) then CheckLock; end; procedure TX86Disassembler.DoGroup2; const OPC: array[0..7] of TOpCode = (OProl, OPror, OPrcl, OPrcr, OPshl, OPshr, OPsal, OPsar); var Index: Byte; begin Include(Flags, flagModRM); Index := (Code[ModRMIdx] shr 3) and 7; Instruction^.Opcode := OPC[Index]; case Code[CodeIdx] of $C0: begin AddEb; AddIb; end; $C1: begin AddEv; AddIb; end; $D0: begin AddEb; AddOperand('1', os8); end; $D1: begin AddEv; AddOperand('1', os8); end; $D2: begin AddEb; AddOperand('cl', os8); end; $D3: begin AddEv; AddOperand('cl', os8); end; else Instruction^.Opcode := OPX_NotGroup2; end; end; procedure TX86Disassembler.DoGroup3; const OPC: array[0..7] of TOpCode = (OPtest, OPtest, OPnot, OPneg, OPmul, OPimul, OPdiv, OPidiv); var Index: Byte; begin Include(Flags, flagModRM); Index := (Code[ModRMIdx] shr 3) and 7; Instruction^.Opcode := OPC[Index]; case Code[CodeIdx] of $F6: begin if (Index = 0) or (Index = 1) then begin AddEb; AddIb; end else begin AddEb; end; end; $F7: begin if (Index = 0) or (Index = 1) then begin AddEv; AddIz; end else begin AddEv; end; end; else Instruction^.Opcode := OPX_NotGroup3; Exit; end; if (Index = 2) or (Index = 3) then CheckLock; end; procedure TX86Disassembler.DoGroup4; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $FE then begin Instruction^.Opcode := OPX_NotGroup4; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case Index of 0: Instruction^.Opcode := OPinc; 1: Instruction^.Opcode := OPdec; else Instruction^.Opcode := OPX_Group4; Exit; end; AddEb; CheckLock; end; procedure TX86Disassembler.DoGroup5; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $FF then begin Instruction^.Opcode := OPX_NotGroup5; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case Index of 0: begin AddEv; Instruction^.Opcode := OPinc; end; 1: begin AddEv; Instruction^.Opcode := OPdec; end; 2: begin Force64; AddEv; Instruction^.Opcode := OPcall; end; 3: begin AddMp; Instruction^.Opcode := OPcall; end; 4: begin Force64; AddEv; Instruction^.Opcode := OPjmp; end; 5: begin AddMp; Instruction^.Opcode := OPjmp; end; 6: begin Default64; AddEv; Instruction^.Opcode := OPpush; end; else Instruction^.Opcode := OPX_Group5; end; if Index in [0,1] then CheckLock; end; procedure TX86Disassembler.DoGroup6; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $00 then begin Instruction^.Opcode := OPX_NotGroup5; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case Index of 0: begin AddMw_Rv; Instruction^.Opcode := OPsldt; end; 1: begin AddMw_Rv; Instruction^.Opcode := OPstr; end; 2: begin AddEw; Instruction^.Opcode := OPlldt; end; 3: begin AddEw; Instruction^.Opcode := OPltr; end; 4: begin AddEw; Instruction^.Opcode := OPverr; end; 5: begin AddEw; Instruction^.Opcode := OPverw; end; else Instruction^.Opcode := OPX_Group6; end; end; procedure TX86Disassembler.DoGroup7; const RM3: array [0..7] of TOpCode = (OPvmrun, OPvmmcall, OPvmload, OPvmsave, OPstgi, OPclgi, OPskinit, OPinvlpga); var Mode: Byte; Index: Byte; RM: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $01 then begin Instruction^.Opcode := OPX_NotGroup7; Exit; end; Mode := (Code[ModRMIdx] shr 6) and 3; Index := (Code[ModRMIdx] shr 3) and 7; RM := (Code[ModRMIdx] ) and 7; case Index of 0: begin AddMs; Instruction^.Opcode := OPsgdt; end; 1: begin AddMs; Instruction^.Opcode := OPsidt; end; 2: begin AddMs; Instruction^.Opcode := OPlgdt; end; 3: begin if Mode = 3 then begin Instruction^.Opcode := RM3[RM]; end else begin AddMs; Instruction^.Opcode := OPlidt; end; end; 4: begin AddMw_Rv; Instruction^.Opcode := OPsmsw; end; //5 : invalid 6: begin AddEw; Instruction^.Opcode := OPlmsw; end; 7: begin if Mode = 3 then begin case RM of 0: Instruction^.Opcode := OPswapgs; 1: Instruction^.Opcode := OPrdtscp; else Instruction^.Opcode := OPX_Group7; end; end else begin AddMb; Instruction^.Opcode := OPinvlpg; end; end; else Instruction^.Opcode := OPX_Group7; end; end; procedure TX86Disassembler.DoGroup8; const RM8: array [0..7] of TOpCode = (OPX_Group8, OPX_Group8, OPX_Group8, OPX_Group8, OPbt, OPbts, OPbtr, OPbtc); var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $BA then begin Instruction^.Opcode := OPX_NotGroup8; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; if Index < 4 then begin Instruction^.Opcode := OPX_Group8; Exit; end; AddEv; AddIb; Instruction^.Opcode := RM8[Index]; if Index in [5..7] then CheckLock; end; procedure TX86Disassembler.DoGroup9; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $C7 then begin Instruction^.Opcode := OPX_NotGroup9; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; if Index = 1 then begin if OperandSize = os64 then begin Instruction^.Opcode := OPcmpxchg16b; AddMdq; end else begin Instruction^.Opcode := OPcmpxchg8b; AddMq; end; CheckLock; end else begin Instruction^.Opcode := OPX_Group9; end; end; procedure TX86Disassembler.DoGroup10; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $B9 then begin Instruction^.Opcode := OPX_NotGroup10; Exit; end; // whole goup is invalid ?? Instruction^.Opcode := OPX_Group10; end; procedure TX86Disassembler.DoGroup11; var Index: Byte; begin Include(Flags, flagModRM); Index := (Code[ModRMIdx] shr 3) and 7; if Index <> 0 then begin Instruction^.Opcode := OPX_NotGroup11; Exit; end; case Code[CodeIdx] of $C6: begin AddEb; AddIb; end; $C7: begin AddEv; AddIz; end; else Instruction^.Opcode := OPX_Group11; Exit; end; Instruction^.Opcode := OPmov; end; procedure TX86Disassembler.DoGroup12; const OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrlw, OPX_Invalid, OPpsraw, OPX_Invalid, OPpsllw, OPX_Invalid); var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $71 then begin Instruction^.Opcode := OPX_NotGroup12; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case DecodePrefix(OPC[Index], OPC[Index], OPX_Invalid, OPX_Invalid) of soNone: begin AddPRq; AddIb; end; so66: begin AddVRdq; AddIb; end; else Instruction^.Opcode := OPX_Group12; end; end; procedure TX86Disassembler.DoGroup13; const OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrld, OPX_Invalid, OPpsrad, OPX_Invalid, OPpslld, OPX_Invalid); var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $72 then begin Instruction^.Opcode := OPX_NotGroup13; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case DecodePrefix(OPC[Index], OPC[Index], OPX_Invalid, OPX_Invalid) of soNone: begin AddPRq; AddIb; end; so66: begin AddVRdq; AddIb; end; else Instruction^.Opcode := OPX_Group13; end; end; procedure TX86Disassembler.DoGroup14; const OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrlq, OPpsrldq, OPX_Invalid, OPX_Invalid, OPpsllq, OPpsrldq); var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $73 then begin Instruction^.Opcode := OPX_NotGroup14; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case DecodePrefix(OPC[Index], OPC[Index], OPX_Invalid, OPX_Invalid) of soNone: begin if (Index = 3) or (Index = 7) then Instruction^.Opcode := OPX_Group14 else begin AddPRq; AddIb; end; end; so66: begin AddVRdq; AddIb; end; else Instruction^.Opcode := OPX_Group14; end; end; procedure TX86Disassembler.DoGroup15; var Index: Byte; Mode: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $AE then begin Instruction^.Opcode := OPX_NotGroup15; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; if (Flags * [pre66, preF3, preF2] <> []) or (Index = 4) then begin Instruction^.Opcode := OPX_Group15; Exit; end; Mode := (Code[ModRMIdx] shr 6) and 3; case Index of 0: begin Instruction^.Opcode := OPfxsave; AddM; end; 1: begin Instruction^.Opcode := OPfxrstor; AddM; end; 2: begin Instruction^.Opcode := OPldmxcsr; AddMd; end; 3: begin Instruction^.Opcode := OPstmxcsr; AddMd; end; 5: Instruction^.Opcode := OPlfence; 6: Instruction^.Opcode := OPmfence; 7: if Mode = 3 then Instruction^.Opcode := OPlfence else begin Instruction^.Opcode := OPclflush; AddMb; end; end; end; procedure TX86Disassembler.DoGroup16; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $18 then begin Instruction^.Opcode := OPX_NotGroup16; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; if Index=0 then ; Instruction^.Opcode := OPX_Invalid; end; procedure TX86Disassembler.DoGroupP; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $0D then begin Instruction^.Opcode := OPX_NotGroupP; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case Index of 0: Instruction^.Opcode := OPprefetch_exclusive; 1,3: Instruction^.Opcode := OPprefetch_modified; else Instruction^.Opcode := OPX_prefetch; end; end; procedure TX86Disassembler.Do2ByteOpcode; const INVALID = '**2byte**'; const OPR_6x: array[0..$F] of TOpCode = ( OPpunpcklbw, OPpunpcklwd, OPpunpcklqd, OPpacksswb, OPpcmpgtb, OPpcmpgtw, OPpcmpgtd, OPpackuswb, OPpunpkhbw, OPpunpkhwd, OPpunpkhdq, OPpackssdw, OPpunpcklqdq, OPpunpckhqdq, OPX_Invalid, OPX_Invalid ); OPR_Dx: array[0..$F] of TOpCode = ( OPX_Invalid, OPpsrlw, OPpsrld, OPpsrlq, OPpaddq, OPpmullw, OPX_Invalid, OPX_Invalid, OPpsubusb, OPpsubusw, OPpminub, OPpand, OPpaddusb, OPpaddusw, OPpmaxub, OPpandn ); OPR_Ex: array[0..$F] of TOpCode = ( OPpavgb, OPpsraw, OPpsrad, OPpavgw, OPpmulhuw, OPpmulhw, OPX_Invalid, OPX_Invalid, OPpsubsb, OPpsubsw, OPpminsw, OPpor, OPpaddsb, OPpaddsw, OPpmaxsw, OPpxor ); OPR_Fx: array[0..$F] of TOpCode = ( OPX_Invalid, OPpsllw, OPpslld, OPpsllq, OPpmuludq, OPpmaddwd, OPpsadbw, OPX_Invalid, OPpsubb, OPpsubw, OPpsubd, OPpsubq, OPpaddb, OPpaddw, OPpaddd, OPX_Invalid ); var idx: Integer; begin Inc(CodeIdx); Inc(ModRMIdx); case Code[CodeIdx] of $00: begin DoGroup6; end; $01: begin DoGroup7; end; $02: begin Instruction^.Opcode := OPlar; AddGv; AddEw; end; $03: begin Instruction^.Opcode := OPlsl; AddGv; AddEw; end; // $04: invalid $05: begin Instruction^.Opcode := OPsyscall; end; $06: begin Instruction^.Opcode := OPclts; end; $07: begin Instruction^.Opcode := OPsysret; end; $08: begin Instruction^.Opcode := OPinvd; end; $09: begin Instruction^.Opcode := OPwbinvd; end; // $0A: invalid $0B: begin Instruction^.Opcode := OPud2; end; // $0C: invalid $0D: begin DoGroupP; end; $0E: begin Instruction^.Opcode := OPfemms; end; $0F: begin Do3DNow; end; //--- $10: begin case DecodePrefix(OPmovups, OPmovupd, OPmovsd, OPmovss) of soNone: begin AddVps; AddWps; end; so66: begin AddVpd; AddWpd; end; soF2: begin AddVdq_sd; AddWsd; end; soF3: begin AddVdq_ss; AddWss; end; end; end; $11: begin case DecodePrefix(OPmovups, OPmovupd, OPmovsd, OPmovss) of soNone: begin AddWps; AddVps; end; so66: begin AddWpd; AddVpd; end; soF2: begin AddWsd; AddVsd; end; soF3: begin AddWss; AddVss; end; end; end; $12: begin case DecodePrefix(OPmovhlps, OPmovlpd, OPmovddup, OPmovsldup) of soNone: begin // Instruction^.Opcode differs on type found // it is specified as Mq or VRq // So when getting Wq, we Add both and know the type AddVps; AddWq; if ofMemory in Instruction^.Operand[2].Flags then Instruction^.Opcode := OPmovlps; end; so66: begin AddVsd; AddMq; end; soF2: begin AddVpd; AddWsd; end; soF3: begin AddVps; AddWps; end; end; end; $13: begin case DecodePrefix(OPmovlps, OPmovlpd, OPX_Invalid, OPX_Invalid) of soNone: begin AddMq; AddVps; end; so66: begin AddMq; AddVsd; end; end; end; $14: begin case DecodePrefix(OPunpcklps, OPunpcklpd, OPX_Invalid, OPX_Invalid) of soNone: begin AddVps; AddWq; end; so66: begin AddVpd; AddWq; end; end; end; $15: begin case DecodePrefix(OPunpckhps, OPunpckhpd, OPX_Invalid, OPX_Invalid) of soNone: begin AddVps; AddWq; end; so66: begin AddVpd; AddWq; end; end; end; $16: begin case DecodePrefix(OPmovlhps, OPmovhpd, OPX_Invalid, OPmovshdup) of soNone: begin // Instruction^.Opcode differs on type found // it is specified as Mq or VRq // So when getting Wq, we Add both and know the type AddVps; AddWq; if ofMemory in Instruction^.Operand[2].Flags then Instruction^.Opcode := OPmovhps; end; so66: begin AddVsd; AddMq; end; soF3: begin AddVps; AddWps; end; end; end; $17: begin case DecodePrefix(OPmovhps, OPmovhpd, OPX_Invalid, OPX_Invalid) of soNone: begin AddMq; AddVps; end; so66: begin AddMq; AddVsd; end; end; end; $18: begin DoGroup16; end; $19..$1F: begin Instruction^.Opcode := OPnop; AddEv; end; //--- $20: begin Instruction^.Opcode := OPmov; AddRd_q; AddCd_q; end; $21: begin Instruction^.Opcode := OPmov; AddRd_q; AddDd_q; end; $22: begin Instruction^.Opcode := OPmov; AddCd_q; AddRd_q; end; $23: begin Instruction^.Opcode := OPmov; AddDd_q; AddRd_q; end; // $24..$27: OPX_Invalid $28: begin case DecodePrefix(OPmovaps, OPmovapd, OPX_Invalid, OPX_Invalid) of soNone: begin AddVps; AddWps; end; so66: begin AddVpd; AddWpd; end; end; end; $29: begin case DecodePrefix(OPmovaps, OPmovapd, OPX_Invalid, OPX_Invalid) of soNone: begin AddWps; AddVps; end; so66: begin AddWpd; AddVpd; end; end; end; $2A: begin case DecodePrefix(OPcvtpi2ps, OPcvtpi2pd, OPcvtsi2sd, OPcvtsi2ss) of soNone: begin AddVps; AddQq; end; so66: begin AddVpd; AddQq; end; soF2: begin AddVsd; AddEd_q; end; soF3: begin AddVss; AddEd_q; end; end; end; $2B: begin case DecodePrefix(OPmovntps, OPmovntpd, OPX_Invalid, OPX_Invalid) of soNone: begin AddMdq; AddVps; end; so66: begin AddMdq; AddVpd; end; end; end; $2C: begin case DecodePrefix(OPcvttps2pi, OPcvttpd2pi, OPcvttsd2si, OPcvttss2si) of soNone: begin AddPq; AddWps; end; so66: begin AddPq; AddWpd; end; soF2: begin AddGd_q; AddWsd; end; soF3: begin AddGd_q; AddWss; end; end; end; $2D: begin case DecodePrefix(OPcvtps2pi, OPcvtpd2pi, OPcvtsd2si, OPcvtss2si) of soNone: begin AddPq; AddWps; end; so66: begin AddPq; AddWpd; end; soF2: begin AddGd_q; AddWsd; end; soF3: begin AddGd_q; AddWss; end; end; end; $2E: begin case DecodePrefix(OPucomiss, OPucomissd, OPX_Invalid, OPX_Invalid) of soNone: begin AddVss; AddWss; end; so66: begin AddVsd; AddWsd; end; end; end; $2F: begin case DecodePrefix(OPcomiss, OPcomissd, OPX_Invalid, OPX_Invalid) of soNone: begin AddVss; AddWss; end; so66: begin AddVsd; AddWsd; end; end; end; //--- $30: begin Instruction^.Opcode := OPwrmsr; end; $31: begin Instruction^.Opcode := OPrdtsc; end; $32: begin Instruction^.Opcode := OPrdmsr; end; $33: begin Instruction^.Opcode := OPrdpmc; end; $34: begin Instruction^.Opcode := OPXsysenter; end; $35: begin Instruction^.Opcode := OPXsysexit; end; // $36..$3F: OPX_Invalid //--- $40..$4F: begin Instruction^.Opcode := OPcmov__; StdCond(Code[CodeIdx]); AddGv; AddEv; end; //--- $50: begin case DecodePrefix(OPmovmskps, OPmovmskpd, OPX_Invalid, OPX_Invalid) of soNone: begin AddGd; AddVRps; end; so66: begin AddGd; AddVRpd; end; end; end; $51..$59, $5C..$5F: begin case Code[CodeIdx] of $51: DecodePrefix(OPsqrtps, OPsqrtpd, OPsqrtsd, OPsqrtss); $52: DecodePrefix(OPrsqrtps, OPX_Invalid, OPX_Invalid, OPrsqrtss); $53: DecodePrefix(OPrcpps, OPX_Invalid, OPX_Invalid, OPrcpss); $54: DecodePrefix(OPandps, OPandpd, OPX_Invalid, OPX_Invalid); $55: DecodePrefix(OPandnps, OPandnpd, OPX_Invalid, OPX_Invalid); $56: DecodePrefix(OPorps, OPorpd, OPX_Invalid, OPX_Invalid); $57: DecodePrefix(OPxorps, OPxorpd, OPX_Invalid, OPX_Invalid); $58: DecodePrefix(OPaddps, OPaddpd, OPaddsd, OPaddss); $59: DecodePrefix(OPmulps, OPmulpd, OPmulsd, OPmulss); $5C: DecodePrefix(OPsubps, OPsubpd, OPsubsd, OPsubss); $5D: DecodePrefix(OPminps, OPminpd, OPminsd, OPminss); $5E: DecodePrefix(OPdivps, OPdivpd, OPdivsd, OPdivss); $5F: DecodePrefix(OPmaxps, OPmaxpd, OPmaxsd, OPmaxss); end; case SimdOpcode of soNone: begin AddVps; AddWps; end; so66: begin AddVpd; AddWpd; end; soF2: begin AddVsd; AddWsd; end; soF3: begin AddVss; AddWss; end; end; end; $5A: begin case DecodePrefix(OPcvtps2pd, OPcvtpd2ps, OPcvtsd2ss, OPcvtss2sd) of soNone: begin AddVpd; AddWps; end; so66: begin AddVps; AddWpd; end; soF2: begin AddVss; AddWsd; end; soF3: begin AddVsd; AddWss; end; end; end; $5B: begin case DecodePrefix(OPcvtdq2ps, OPcvtps2dq, OPX_Invalid, OPcvttps2dq) of soNone: begin AddVps; AddWdq; end; so66: begin AddVdq; AddWps; end; soF3: begin AddVdq; AddWps; end; end; end; // $5C..$5F: see $51 //--- $60..$6D: begin idx := Code[CodeIdx] and $F; CheckSIMD; case DecodePrefix(OPR_6x[idx], OPR_6x[idx], OPX_Invalid, OPX_Invalid) of soNone: begin if Code[CodeIdx] in [$6C, $6D] then Instruction^.Opcode := OPX_Invalid else begin AddPq; AddQd; end; end; so66: begin AddVdq; if Code[CodeIdx] = $6B then AddWdq else AddWq; end; end; end; $6E: begin case DecodePrefix(OPmovd, OPmovd, OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddEd_q; end; so66: begin AddVdq; AddEd_q; end; end; end; $6F: begin case DecodePrefix(OPmovq, OPmovdqa, OPX_Invalid, OPmovdqu) of soNone: begin AddPq; AddQq; end; so66: begin AddVdq; AddWdq; end; soF3: begin AddVdq; AddWdq; end; end; end; //--- $70: begin case DecodePrefix(OPpshufw, OPpshufd, OPpshuflw, OPpshufhw) of soNone: begin AddPq; AddQq; AddIb; end; so66: begin AddVdq; AddWdq; AddIb; end; soF2: begin AddVq; AddWq; AddIb; end; soF3: begin AddVq; AddWq; AddIb; end; end; end; $71: begin if Flags * [preF3, preF2] = [] then DoGroup12 else Instruction^.Opcode := OPX_Invalid; end; $72: begin if Flags * [preF3, preF2] = [] then DoGroup13 else Instruction^.Opcode := OPX_Invalid; end; $73: begin if Flags * [preF3, preF2] = [] then DoGroup14 else Instruction^.Opcode := OPX_Invalid; end; $74: begin case DecodePrefix(OPpcmpeqb, OPpcmpeqb, OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddQq; end; so66: begin AddVdq; AddWdq; end; end; end; $75: begin case DecodePrefix(OPpcmpeqw, OPpcmpeqw, OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddQq; end; so66: begin AddVdq; AddWdq; end; end; end; $76: begin case DecodePrefix(OPpcmpeqd, OPpcmpeqd, OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddQq; end; so66: begin AddVdq; AddWdq; end; end; end; $77: begin if Flags * [preF3, preF2, pre66] = [] then Instruction^.Opcode := OPemms else Instruction^.Opcode := OPX_Invalid; end; // $78..$7B: OPX_Invalid $7C: begin case DecodePrefix(OPX_Invalid, OPhaddpd, OPhaddps, OPX_Invalid) of so66: begin AddVpd; AddWpd; end; soF2: begin AddVps; AddWps; end; end; end; $7D: begin case DecodePrefix(OPX_Invalid, OPhsubpd, OPhsubps, OPX_Invalid) of so66: begin AddVpd; AddWpd; end; soF2: begin AddVps; AddWps; end; end; end; $7E: begin case DecodePrefix(OPmovd, OPmovd, OPX_Invalid, OPmovq) of soNone: begin AddEd_q; AddPd_q; end; so66: begin AddEd_q; AddVd_q; end; soF3: begin AddVq; AddWq; end; end; end; $7F: begin case DecodePrefix(OPmovq, OPmovdqa, OPX_Invalid, OPmovdqu) of soNone: begin AddQq; AddPq; end; so66: begin AddWdq; AddVdq; end; soF3: begin AddWdq; AddVdq; end; end; end; //--- $80..$8F: begin Force64; Instruction^.Opcode := OPj__; StdCond(Code[CodeIdx]); AddJz; end; //--- $90..$9F: begin Instruction^.Opcode := OPset__; StdCond(Code[CodeIdx]); AddEb; end; //--- $A0: begin Default64; Instruction^.Opcode := OPpush; AddOperand('fs'); end; $A1: begin Default64; Instruction^.Opcode := OPpop; AddOperand('fs'); end; $A2: begin Instruction^.Opcode := OPcpuid; end; $A3: begin Instruction^.Opcode := OPbt; AddEv; AddGv; end; $A4: begin Instruction^.Opcode := OPshld; AddEv; AddGv; AddIb; end; $A5: begin Instruction^.Opcode := OPshld; AddEv; AddGv; AddOperand('cl'); end; // $A6..$A7: OPX_Invalid $A8: begin Default64; Instruction^.Opcode := OPpush; AddOperand('gs'); end; $A9: begin Default64; Instruction^.Opcode := OPpop; AddOperand('gs'); end; $AA: begin Instruction^.Opcode := OPrsm; end; $AB: begin Instruction^.Opcode := OPbts; AddEv; AddGv; end; $AC: begin Instruction^.Opcode := OPshrd; AddEv; AddGv; AddIb; end; $AD: begin Instruction^.Opcode := OPshld; AddEv; AddGv; AddOperand('cl'); end; $AE: begin DoGroup15; end; $AF: begin Instruction^.Opcode := OPimul; AddGv; AddEv; end; //--- $B0: begin AddEb; AddGb; Instruction^.Opcode := OPcmpxchg; CheckLock; end; $B1: begin AddEv; AddGv; Instruction^.Opcode := OPcmpxchg; CheckLock; end; $B2: begin Instruction^.Opcode := OPlss; AddGz; AddMp; end; $B3: begin Instruction^.Opcode := OPbtr; AddEv; AddGv; end; $B4: begin Instruction^.Opcode := OPlfs; AddGz; AddMp; end; $B5: begin Instruction^.Opcode := OPlgs; AddGz; AddMp; end; $B6: begin Instruction^.Opcode := OPmovzx; AddGv; AddEb; end; $B7: begin Instruction^.Opcode := Opmovzx; AddGv; AddEw; end; // $B8: OPX_Invalid $B9: begin DoGroup10; end; $BA: begin DoGroup8; end; $BB: begin Instruction^.Opcode := OPbtc; AddEv; AddGv; end; $BC: begin Instruction^.Opcode := OPbsf; AddGv; AddEv; end; $BD: begin Instruction^.Opcode := OPbsr; AddGv; AddEv; end; $BE: begin Instruction^.Opcode := OPmovsx; AddGv; AddEb; end; $BF: begin Instruction^.Opcode := OPmovsx; AddGv; AddEw; end; //--- $C0: begin AddEb; AddGb; Instruction^.Opcode := OPxadd; CheckLock; end; $C1: begin AddEv; AddGv; Instruction^.Opcode := OPxadd; CheckLock; end; $C2: begin case DecodePrefix(OPcmpps, OPcmppd, OPcmpsd, OPcmpss) of soNone: begin AddVps; AddWps; AddIb end; so66: begin AddVpd; AddWpd; AddIb end; soF2: begin AddVsd; AddWsd; AddIb end; soF3: begin AddVss; AddWss; AddIb end; end; end; $C3: begin if Flags * [preF3, preF2, pre66] = [] then begin Instruction^.Opcode := OPmovnti; AddMd_q; AddGd_q; end else Instruction^.Opcode := OPX_Invalid; end; $C4: begin case DecodePrefix(OPpinsrw, OPpinsrw, OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddEw; AddIb end; so66: begin AddVdq; AddEw; AddIb end; end; end; $C5: begin case DecodePrefix(OPpextrw, OPpextrw, OPX_Invalid, OPX_Invalid) of soNone: begin AddGd; AddPRq; AddIb end; so66: begin AddGd; AddVRdq; AddIb end; end; end; $C6: begin case DecodePrefix(OPshufps, OPshufpd, OPX_Invalid, OPX_Invalid) of soNone: begin AddVps; AddWps; AddIb end; so66: begin AddVpd; AddWpd; AddIb end; end; end; $C7: begin DoGroup9; end; $C8..$CF: begin Instruction^.Opcode := OPbswp; AddStdReg(Code[CodeIdx]); end; //--- $D0: begin case DecodePrefix(OPX_Invalid, OPaddsubpd, OPaddsubps, OPX_Invalid) of so66: begin AddVpd; AddWpd; end; soF2: begin AddVps; AddWps; end; end; end; $D1..$D5, $D8..$DF: begin idx := Code[CodeIdx] and $F; case DecodePrefix(OPR_Dx[idx], OPR_Dx[idx], OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddQq; end; so66: begin AddVdq; AddWdq; end; end; end; $D6: begin case DecodePrefix(OPX_Invalid, OPmovq, OPmovdq2q, OPmovq2dq) of so66: begin AddWq; AddVq; end; soF2: begin AddPq; AddVRq; end; soF3: begin AddVdq; AddPRq; end; end; end; $D7: begin case DecodePrefix(OPpmovmskb, OPpmovmskb, OPX_Invalid, OPX_Invalid) of soNone: begin AddGd; AddPRq; end; so66: begin AddGd; AddVRdq; end; end; end; // $D8..$DF: see $D1 //--- $E0..$E5, $E8..$EF: begin idx := Code[CodeIdx] and $F; case DecodePrefix(OPR_Ex[idx], OPR_Ex[idx], OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddQq; end; so66: begin AddVdq; AddWdq; end; end; end; $E6: begin case DecodePrefix(OPX_Invalid, OPcvttpd2dq, OPcvtpd2dq, OPcvtdq2pd) of so66: begin AddVq; AddWpd; end; soF2: begin AddVq; AddWpd; end; soF3: begin AddVpd; AddWq; end; end; end; $E7: begin case DecodePrefix(OPmovntq, OPmovntdqu, OPX_Invalid, OPX_Invalid) of soNone: begin AddMq; AddPq; end; so66: begin AddMdq; AddVdq; end; end; end; // $E8..$EF: see $E0 $F0: begin if preF2 in Flags then begin Instruction^.Opcode := OPlddqu; AddVpd; AddMdq; end else Instruction^.Opcode := OPX_Invalid; end; $F1..$F6, $F8..$FE: begin idx := Code[CodeIdx] and $F; case DecodePrefix(OPR_Fx[idx], OPR_Fx[idx], OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddQq; end; so66: begin AddVdq; AddWdq; end; end; end; $F7: begin case DecodePrefix(OPmaskmovq, OPmaskmovdqu, OPX_Invalid, OPX_Invalid) of soNone: begin AddPq; AddPRq; end; so66: begin AddVdq; AddVRdq; end; end; end; // $F8..$FE: see $F1 // $FF: OPX_Invalid else Instruction^.Opcode := OPX_Invalid; end; end; procedure TX86Disassembler.DoDisassemble; begin Instruction^.Opcode := OPX_InternalUnknown; repeat ModRMIdx := CodeIdx + 1; case Code[CodeIdx] of $00..$05: begin AddStdOperands(Code[CodeIdx]); Instruction^.Opcode := OPadd; CheckLock; end; $06: begin Instruction^.Opcode := OPpush; Check32; AddOperand('es'); end; $07: begin Instruction^.Opcode := OPpop; Check32; AddOperand('es'); end; $08..$0D: begin AddStdOperands(Code[CodeIdx]); Instruction^.Opcode := OPor; CheckLock; end; $0E: begin Instruction^.Opcode := OPpush; Check32; AddOperand('cs'); end; $0F: begin Do2ByteOpcode; end; //--- $10..$15: begin AddStdOperands(Code[CodeIdx]); Instruction^.Opcode := OPadc; CheckLock; end; $16: begin Instruction^.Opcode := OPpush; Check32; AddOperand('ss'); end; $17: begin Instruction^.Opcode := OPpop; Check32; AddOperand('ss'); end; $18..$1D: begin AddStdOperands(Code[CodeIdx]); Instruction^.Opcode := OPsbb; CheckLock; end; $1E: begin Instruction^.Opcode := OPpush; Check32; AddOperand('ds'); end; $1F: begin Instruction^.Opcode := OPpop; Check32; AddOperand('ds'); end; //--- $20..$25: begin AddStdOperands(Code[CodeIdx]); Instruction^.Opcode := OPand; CheckLock; end; $26: begin Instruction^.Segment := Instruction^.Segment + Ignore64('es:'); end; $27: begin Instruction^.Opcode := OPdaa; Check32; end; $28..$2D: begin AddStdOperands(Code[CodeIdx]); Instruction^.Opcode := OPsub; CheckLock; end; $2E: begin Instruction^.Segment := Instruction^.Segment + Ignore64('cs:'); end; $2F: begin Instruction^.Opcode := OPdas; Check32; end; //--- $30..$35: begin AddStdOperands(Code[CodeIdx]); Instruction^.Opcode := OPxor; CheckLock; end; $36: begin Instruction^.Segment := Instruction^.Segment + Ignore64('ss:'); end; $37: begin Instruction^.Opcode := OPaaa; Check32; end; $38..$3D: begin Instruction^.Opcode := OPcmp; AddStdOperands(Code[CodeIdx]); end; $3E: begin Instruction^.Segment := Instruction^.Segment + Ignore64('ds:'); end; $3F: begin Instruction^.Opcode := OPaas; Check32; end; //--- $40..$4F: begin if (ProcessMode = dm64) then begin if (Code[CodeIdx] and 1) <> 0 then Include(Flags, rexB); if (Code[CodeIdx] and 2) <> 0 then Include(Flags, rexX); if (Code[CodeIdx] and 4) <> 0 then Include(Flags, rexR); if (Code[CodeIdx] and 8) <> 0 then Include(Flags, rexW); Include(Flags, flagRex); end else begin AddStdReg(Code[CodeIdx]); if Code[CodeIdx] <= $47 then Instruction^.Opcode := OPinc else Instruction^.Opcode := OPdec; CheckLock; end; end; //--- $50..$57: begin Default64; Instruction^.Opcode := OPpush; AddStdReg(Code[CodeIdx]); end; $58..$5F: begin Default64; Instruction^.Opcode := OPpop; AddStdReg(Code[CodeIdx]); end; //--- $60: begin if OperandSize = os16 then Instruction^.Opcode := OPpusha else Instruction^.Opcode := OPpushad; Check32; end; $61: begin if OperandSize = os16 then Instruction^.Opcode := OPpopa else Instruction^.Opcode := OPpopad; Check32; end; $62: begin Instruction^.Opcode := OPbound; Check32; AddGv; AddMa; end; $63: begin if (ProcessMode = dm64) then begin Instruction^.Opcode := (OPmovsxd); AddGv; AddEd; end else begin Instruction^.Opcode := OParpl; Check32; AddEw; AddGw; end; end; $64: begin Instruction^.Segment := Instruction^.Segment + 'fs:'; end; $65: begin Instruction^.Segment := Instruction^.Segment + 'gs:'; end; $66: begin Include(FLags, pre66); end; $67: begin Include(FLags, preAdr); end; $68: begin Default64; Instruction^.Opcode := OPpush; AddIz; end; $69: begin Instruction^.Opcode := OPimul; AddGv; AddEv; AddIz; end; $6A: begin Default64; Instruction^.Opcode := OPpush; AddIb; end; $6B: begin Instruction^.Opcode := OPimul; AddGv; AddEv; AddIb; end; $6C: begin Instruction^.Opcode := OPinsb; CheckRepeat; {$ifdef verbose_string_instructions} AddYb; AddOperand('dx', os16); {$endif} end; $6D: begin if OperandSize = os16 then Instruction^.Opcode := OPinsw else Instruction^.Opcode := OPinsd; CheckRepeat; {$ifdef verbose_string_instructions} AddYz; AddOperand('dx', os16); {$endif} end; $6E: begin Instruction^.Opcode := OPoutsb; CheckRepeat; {$ifdef verbose_string_instructions} AddOperand('dx', os16); AddXb; {$endif} end; $6F: begin if OperandSize = os16 then Instruction^.Opcode := OPoutsw else Instruction^.Opcode := OPoutsd; CheckRepeat; {$ifdef verbose_string_instructions} AddOperand('dx', os16); AddXz; {$endif} end; $70..$7F: begin Force64; Instruction^.Opcode := OPj__; StdCond(Code[CodeIdx]); AddJb; end; //--- $80..$83: begin DoGroup1; end; $84: begin Instruction^.Opcode := OPtest; AddEb; AddGb; end; $85: begin Instruction^.Opcode := OPtest; AddEv; AddGv; end; $86: begin AddEb; AddGb; Instruction^.Opcode := OPxchg; CheckLock; end; $87: begin AddEv; AddGv; Instruction^.Opcode := OPxchg; CheckLock; end; $88..$8B: begin Instruction^.Opcode := OPmov; AddStdOperands(Code[CodeIdx]); end; $8C: begin Instruction^.Opcode := OPmov; AddMw_Rv; AddSw; end; $8D: begin Instruction^.Opcode := OPlea; AddGv; AddM; end; $8E: begin Instruction^.Opcode := OPmov; AddSw; AddEw; end; $8F: begin Default64; DoGroup1; end; //--- $90..$97: begin if (Code[CodeIdx] = $90) and not (rexB in Flags) then Instruction^.Opcode := OPnop else begin Instruction^.Opcode := OPxchg; AddStdReg(Code[CodeIdx]); AddOperand(SizeReg32('ax')); end; end; $98: begin case OperandSize of os64: Instruction^.Opcode := OPcdqe; os32: Instruction^.Opcode := OPcwde; else Instruction^.Opcode := OPcbw; end; end; $99: begin case OperandSize of os64: Instruction^.Opcode := OPcqo; os32: Instruction^.Opcode := OPcqd; else Instruction^.Opcode := OPcwd; end; end; $9A: begin Instruction^.Opcode := OPcall; Check32; AddAp; end; $9B: begin Instruction^.Opcode := OPwait_fwait; end; $9C: begin Default64; case OperandSize of os64: Instruction^.Opcode := OPpushfq; os32: Instruction^.Opcode := OPpushfd; else Instruction^.Opcode := OPpushf; end; AddFv; end; $9D: begin Default64; case OperandSize of os64: Instruction^.Opcode := OPpopfq; os32: Instruction^.Opcode := OPpopfd; else Instruction^.Opcode := OPpopf; end; AddFv; end; $9E: begin Instruction^.Opcode := OPsahf; end; $9F: begin Instruction^.Opcode := OPlahf; end; //--- $A0: begin Instruction^.Opcode := OPmov; AddOperand('al', os8); AddOb; end; $A1: begin Instruction^.Opcode := OPmov; AddOperand(SizeReg32('ax')); AddOv; end; $A2: begin Instruction^.Opcode := OPmov; AddOb; AddOperand('al', os8); end; $A3: begin Instruction^.Opcode := OPmov; AddOv; AddOperand(SizeReg32('ax')); end; $A4: begin Instruction^.Opcode := OPmovsb; CheckRepeat; {$ifdef verbose_string_instructions} AddYb; AddXb; {$endif} end; $A5: begin case OperandSize of os64: Instruction^.Opcode := OPmovsq; os32: Instruction^.Opcode := OPmovsd; else Instruction^.Opcode := OPmovsw; end; CheckRepeat; {$ifdef verbose_string_instructions} AddYv; AddXv; {$endif} end; $A6: begin Instruction^.Opcode := OPcmpsb; CheckRepeatX; {$ifdef verbose_string_instructions} AddXb; AddYb; {$endif} end; $A7: begin case OperandSize of os64: Instruction^.Opcode := OPcmpsq; os32: Instruction^.Opcode := OPcmpsd; else Instruction^.Opcode := OPcmpsw; end; CheckRepeatX; {$ifdef verbose_string_instructions} AddYv; AddXv; {$endif} end; $A8: begin Instruction^.Opcode := OPtest; AddOperand('al', os8); AddIb; end; $A9: begin Instruction^.Opcode := OPtest; AddOperand(SizeReg32('ax')); AddIv; end; $AA: begin Instruction^.Opcode := OPstosb; CheckRepeat; {$ifdef verbose_string_instructions} AddYb; AddOperand('al', os8); {$endif} end; $AB: begin case OperandSize of os64: Instruction^.Opcode := OPstosq; os32: Instruction^.Opcode := OPstosd; else Instruction^.Opcode := OPstosw; end; CheckRepeat;; {$ifdef verbose_string_instructions} AddYv; AddOperand(SizeReg32('ax')); {$endif} end; $AC: begin Instruction^.Opcode := OPlodsb; CheckRepeat; {$ifdef verbose_string_instructions} AddOperand('al', os8); AddXb; {$endif} end; $AD: begin case OperandSize of os64: Instruction^.Opcode := OPlodsq; os32: Instruction^.Opcode := OPlodsd; else Instruction^.Opcode := OPlodsw; end; CheckRepeat; {$ifdef verbose_string_instructions} AddOperand(SizeReg32('ax')); AddXv; {$endif} end; $AE: begin Instruction^.Opcode := OPscasb; CheckRepeatX; {$ifdef verbose_string_instructions} AddOperand('al', os8); AddYb; {$endif} end; $AF: begin case OperandSize of os64: Instruction^.Opcode := OPscasq; os32: Instruction^.Opcode := OPscasd; else Instruction^.Opcode := OPscasw; end; CheckRepeatX; {$ifdef verbose_string_instructions} AddOperand(SizeReg32('ax')); AddYv; {$endif} end; //--- $B0..$B7: begin Instruction^.Opcode := OPmov; AddStdReg(Code[CodeIdx], reg8); AddIb; end; $B8..$BF: begin Instruction^.Opcode := OPmov; AddStdReg(Code[CodeIdx]); AddIv; end; //--- $C0..$C1: begin DoGroup2; end; $C2: begin Force64; Instruction^.Opcode := OPret; AddIw; end; $C3: begin Force64; Instruction^.Opcode := OPret; end; $C4: begin Instruction^.Opcode := OPles; AddGz; AddMp; end; $C5: begin Instruction^.Opcode := OPlds; AddGz; AddMp; end; $C6..$C7: begin DoGroup11; end; $C8: begin Instruction^.Opcode := OPenter; AddIw; AddIb; end; $C9: begin Default64; Instruction^.Opcode := OPleave; end; $CA: begin Instruction^.Opcode := OPretf; AddIw; end; $CB: begin Instruction^.Opcode := OPretf; end; $CC: begin Instruction^.Opcode := OPint3; end; $CD: begin Instruction^.Opcode := OPint; AddIb; end; $CE: begin Instruction^.Opcode := OPint0; Check32; end; $CF: begin case OperandSize of os64: Instruction^.Opcode := OPiretq; os32: Instruction^.Opcode := OPiretd; else Instruction^.Opcode := OPiret; end; end; //--- $D0..$D3: begin DoGroup2; end; $D4: begin Instruction^.Opcode := OPaam; Check32; end; $D5: begin Instruction^.Opcode := OPaad; Check32; end; $D6: begin Instruction^.Opcode := OPsalc; Check32; end; $D7: begin Instruction^.Opcode := OPxlat; end; $D8..$DF: begin DoX87; end; //--- $E0: begin Force64; Instruction^.Opcode := OPloopne; AddJb; end; $E1: begin Force64; Instruction^.Opcode := OPloope; AddJb; end; $E2: begin Force64; Instruction^.Opcode := OPloop; AddJb; end; $E3: begin Force64; Instruction^.Opcode := OPjrcxz; AddJb; end; $E4: begin Instruction^.Opcode := OPin; AddOperand('al', os8); AddIb; end; $E5: begin Instruction^.Opcode := OPin; AddOperand(SizeReg32('ax')); AddIb; end; $E6: begin Instruction^.Opcode := OPout; AddIb; AddOperand('al', os8); end; $E7: begin Instruction^.Opcode := OPout; AddIb; AddOperand(SizeReg32('ax')); end; $E8: begin Force64; Instruction^.Opcode := OPcall; AddJz; end; $E9: begin Force64; Instruction^.Opcode := OPjmp; AddJz; end; $EA: begin Instruction^.Opcode := OPjmp; Check32; AddAp; end; $EB: begin Force64; Instruction^.Opcode := OPjmp; AddJb; end; $EC: begin Instruction^.Opcode := OPin; AddOperand('al', os8); AddOperand('dx', os16); end; $ED: begin Instruction^.Opcode := OPin; AddOperand(SizeReg32('ax')); AddOperand('dx', os16); end; $EE: begin Instruction^.Opcode := OPout; AddOperand('dx', os16); AddOperand('al', os8); end; $EF: begin Instruction^.Opcode := OPout; AddOperand('dx', os16); AddOperand(SizeReg32('ax')); end; $F0: begin Include(Flags, preLock); end; $F1: begin Instruction^.Opcode := OPint1; end; $F2: begin Include(Flags, preF2); end; $F3: begin Include(Flags, preF3); end; $F4: begin Instruction^.Opcode := OPhlt; end; $F5: begin Instruction^.Opcode := OPcmc; end; $F6..$F7: begin DoGroup3; end; $F8: begin Instruction^.Opcode := OPclc; end; $F9: begin Instruction^.Opcode := OPstc; end; $FA: begin Instruction^.Opcode := OPcli; end; $FB: begin Instruction^.Opcode := OPsti; end; $FC: begin Instruction^.Opcode := OPcld; end; $FD: begin Instruction^.Opcode := OPstd; end; $FE: begin DoGroup4; end; $FF: begin DoGroup5; end; else Instruction^.Opcode := OPX_Invalid; // HexValue(Code[CodeIdx], 1, []); end; Inc(CodeIdx); if CodeIdx > 16 // max instruction length then begin Debugln(DBG_WARNINGS, 'Disassemble: instruction longer than 16 bytes'); Exit; end; until Instruction^.Opcode <> OPX_InternalUnknown; end; procedure TX86Disassembler.Disassemble(AMode: TFPDMode; var AAddress: Pointer; out AnInstruction: TInstruction); var n: Integer; begin ProcessMode := AMode; Code := AAddress; Instruction := @AnInstruction; Instruction^.Opcode := OPX_Invalid; Instruction^.OpCodeSuffix := OPSx_none; Instruction^.Flags := []; Instruction^.Segment := ''; Flags := []; CodeIdx := 0; OperIdx := 0; SimdOpcode := soInvalid; DoDisassemble; Instruction^.OperCnt := OperIdx; Instruction^.ParseFlags := Flags; if flagModRM in Flags then Inc(CodeIdx); if flagSib in Flags then Inc(CodeIdx); for n := 1 to OperIdx do begin AnInstruction.Operand[n].CodeIndex := CodeIdx; Inc(CodeIdx, AnInstruction.Operand[n].ByteCount); Inc(CodeIdx, AnInstruction.Operand[n].ByteCount2); end; Inc(AAddress, CodeIdx); end; { TX86AsmInstruction } procedure TX86AsmInstruction.ReadCode; begin if not (diCodeRead in FFlags) then begin if not FProcess.ReadData(FAddress, INSTR_CODEBIN_LEN, FCodeBin) then Include(FFlags, diCodeReadError); Include(FFlags, diCodeRead); end; end; procedure TX86AsmInstruction.Disassemble; var a: PByte; Disassembler: TX86Disassembler; begin if not (diDisAss in FFlags) then begin ReadCode; if diCodeReadError in FFlags then exit; a := @FCodeBin[0]; Disassembler.Disassemble(FProcess.Mode, a, FInstruction); FInstrLen := a - @FCodeBin[0]; Include(FFlags, diDisAss); end; end; constructor TX86AsmInstruction.Create(AProcess: TDbgProcess); begin FProcess := AProcess; inherited Create; AddReference; end; procedure TX86AsmInstruction.SetAddress(AnAddress: TDBGPtr); begin FAddress := AnAddress; FFlags := []; end; function TX86AsmInstruction.IsCallInstruction: boolean; var a: PByte; begin Result := False; ReadCode; if diCodeReadError in FFlags then exit; a := @FCodeBin[0]; if (FProcess.Mode = dm64) then begin while (a < @FCodeBin[0] + INSTR_CODEBIN_LEN) and (a^ in [$40..$4F, $64..$67]) do inc(a); if not (a^ in [$E8, $FF]) then exit; end else begin while (a < @FCodeBin[0] + INSTR_CODEBIN_LEN) and (a^ in [$26, $2E, $36, $3E, $64..$67]) do inc(a); if not (a^ in [$9A, $E8, $FF]) then exit; end; Disassemble; Result := FInstruction.OpCode = OPcall; end; function TX86AsmInstruction.IsReturnInstruction: boolean; var a: PByte; begin ReadCode; if diCodeReadError in FFlags then exit(False); a := @FCodeBin[0]; // CF: IRET Result := (a^ in [$C2, $C3, $CA, $CB, $CF]); end; function TX86AsmInstruction.IsLeaveStackFrame: boolean; var a: PByte; begin ReadCode; if diCodeReadError in FFlags then exit(False); a := @FCodeBin[0]; // C9: leave Result := (a^ = $C9); if Result then exit; if (FProcess.Mode = dm64) then begin Result := // 48 8D 65 00 / 5D: lea rsp,[rbp+$00] / pop ebp ( (a^ = $48) and (a[1] = $8D) and (a[2] = $65) and (a[3] = $00) and (a[4] = $5D) ) or // 48 89 ec / 5D: mov esp,ebp / pop ebp ( (a^ = $48) and (a[1] = $89) and (a[2] = $EC) and (a[3] = $5D) ); end else begin Result := // 8D 65 00 / 5D: lea rsp,[rbp+$00] / pop ebp ( (a[0] = $8D) and (a[1] = $65) and (a[2] = $00) and (a[3] = $5D) ) or // 89 ec / 5D: mov esp,ebp / pop ebp ( (a[0] = $89) and (a[1] = $EC) and (a[2] = $5D) ); end; end; function TX86AsmInstruction.ModifiesStackPointer: boolean; var a: PByte; begin (* Enter, Leave mov sp, ... lea sp, ... pop / push BUT NOT ret *) Result := False; ReadCode; if diCodeReadError in FFlags then exit; a := @FCodeBin[0]; if (FProcess.Mode = dm64) then begin while (a < @FCodeBin[0] + INSTR_CODEBIN_LEN) and (a^ in [$40..$4F, $64..$67]) do inc(a); // Pop/Push if (a^ in [$50..$61, $68, $8F, $9C, $9d]) then exit(True); end else begin while (a < @FCodeBin[0] + INSTR_CODEBIN_LEN) and (a^ in [$26, $2E, $36, $3E, $64..$67]) do inc(a); // Pop/Push if (a^ in [$06, $07, $0E, $16, $17, $1E, $1F, $50..$61, $68, $6A, $8F, $9C, $9d]) then exit(True); end; // Pop/Push if (a^ in [$FF]) then begin Disassemble; exit(FInstruction.OpCode = OPpush); end; if (a^ = $0F) and (a[1] in [$A0, $A1, $A8, $A9]) then exit(True); // Enter/Leave if (a^ in [$C8, $C9]) then exit(True); // Mov/Lea if (a^ in [$89, $8B, $8D]) and ( ((a[1] and $38) = $20) or ((a[1] and $03) = $04) ) // SP is involved then begin //Disassemble; exit(True); // does report some "false positives" end; end; function TX86AsmInstruction.IsJumpInstruction(IncludeConditional: Boolean; IncludeUncoditional: Boolean): boolean; var a: PByte; begin (* Excluding E1, E2 loop E3 JCXZ Jump short if eCX register is 0 *) Result := False; ReadCode; if diCodeReadError in FFlags then exit; a := @FCodeBin[0]; if IncludeConditional and (a^ in [$70..$7F]) then exit(True); if IncludeConditional and (a^ = $0F) and (a[1] in [$80..$8F]) then exit(True); if IncludeUncoditional and (a^ in [$E9..$EB]) then exit(True); if IncludeUncoditional and (a^ in [$FF]) then begin Disassemble; exit(FInstruction.OpCode = OPjmp); end; end; function TX86AsmInstruction.InstructionLength: Integer; begin Disassemble; if diCodeReadError in FFlags then exit(0); Result := FInstrLen; end; function TX86AsmInstruction.X86OpCode: TOpCode; begin Disassemble; if diCodeReadError in FFlags then exit(OPX_Invalid); Result := FInstruction.OpCode; end; procedure TX86AsmDecoder.Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); const MEMPTR: array[TOperandSize] of string = ('byte ptr ', 'word ptr ', 'dword ptr ', 'qword ptr ', '', 'tbyte ptr ', '16byte ptr '); {$ifdef debug_OperandSize} OSTEXT: array[TOperandSize] of string = ('os8', 'os16', 'os32', 'os64', 'os48', 'os80', 'os128'); {$endif} var Disassembler: TX86Disassembler; Instr: TInstruction; S, Soper: String; n, i: Integer; HasMem: Boolean; OpcodeName: String; Code: PByte; begin Code := AAddress; Disassembler.Disassemble(FProcess.Mode, AAddress, Instr); Soper := ''; HasMem := False; for n := 1 to Instr.OperCnt do begin if Instr.Operand[n].ByteCount = 0 then S := Instr.Operand[n].Value else begin i := Instr.Operand[n].CodeIndex; if Instr.Operand[n].ByteCount2 = 0 then S := Format(Instr.Operand[n].Value, [HexValue(Code[i], Instr.Operand[n].ByteCount, Instr.Operand[n].FormatFlags)]) else S := Format(Instr.Operand[n].Value, [HexValue(Code[i], Instr.Operand[n].ByteCount, Instr.Operand[n].FormatFlags), HexValue(Code[i + Instr.Operand[n].ByteCount], Instr.Operand[n].ByteCount2, Instr.Operand[n].FormatFlags)]) end; if Soper <> '' then Soper := Soper + ','; if ofMemory in Instr.Operand[n].Flags then begin if (Instr.OperCnt = 1) // or (Instr.Operand[n].Size <> os32) or (Instr.Operand[1].Size <> Instr.Operand[2].Size) then Soper := Soper + MEMPTR[Instr.Operand[n].Size]; Soper := Soper + Instr.Segment + '[' + S + ']'; HasMem := True; end else Soper := Soper + S; end; {$ifdef debug_OperandSize} Soper := Soper + ' | '; for n := 1 to OperIdx do begin Soper := Soper + ' ' + OSTEXT[Instr.Operand[n].Size]; end; {$endif} OpcodeName := OPCODE_NAME[Instr.OpCode]; OpcodeName := OpcodeName + OPCODE_SUFFIX_NAME[Instr.OpCodeSuffix]; if Instr.Flags * [ifOnly32, ifOnly64] <> [] then OpcodeName := '**'+OpcodeName + '**'; if ifPrefixRep in Instr.Flags then OpcodeName := 'rep '+OpcodeName ; if ifPrefixRepE in Instr.Flags then OpcodeName := 'repe '+OpcodeName ; if ifPrefixRepNe in Instr.Flags then OpcodeName := 'repne '+OpcodeName ; if ifPrefixLock in Instr.Flags then OpcodeName := 'lock '+OpcodeName ; S := ''; if preLock in Instr.ParseFlags then S := S + '**lock**'; if preF3 in Instr.ParseFlags then S := S + '?rep?'; if preF2 in Instr.ParseFlags then S := S + '?repne?'; S := S + OpcodeName; if not HasMem and (Instr.Segment <> '') then S := S + ' ?' + Instr.Segment + '?'; ACode := S + ' ' + Soper; // memory S := ''; while Code < AAddress do begin S := S + HexStr(Code^, 2); inc(Code); end; ACodeBytes := S; end; function TX86AsmDecoder.GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; begin if (FLastInstr = nil) or (FLastInstr.RefCount > 1) then begin ReleaseRefAndNil(FLastInstr); FLastInstr := TX86AsmInstruction.Create(FProcess); end; FLastInstr.SetAddress(AnAddress); Result := FLastInstr; end; { TX86AsmDecoder } function TX86AsmDecoder.GetLastErrorWasMemReadErr: Boolean; begin Result := FLastErrWasMem; end; function TX86AsmDecoder.GetMaxInstrSize: integer; begin Result := 16; end; function TX86AsmDecoder.GetMinInstrSize: integer; begin Result := 1; end; function TX86AsmDecoder.GetCanReverseDisassemble: boolean; begin {$IFDEF FPDEBUG_WITH_REVERSE_DISASM} Result := true; {$ELSE} Result := False; {$ENDIF} end; function TX86AsmDecoder.ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal ): Boolean; begin Result := FProcess.ReadData(AnAddress, ALen, FCodeBin[0], ALen); FLastErrWasMem := not Result; end; constructor TX86AsmDecoder.Create(AProcess: TDbgProcess); begin FProcess := AProcess; end; destructor TX86AsmDecoder.Destroy; begin ReleaseRefAndNil(FLastInstr); inherited Destroy; end; function TX86AsmDecoder.GetFunctionFrameInfo(AnAddress: TDBGPtr; out AnIsOutsideFrame: Boolean): Boolean; var ADataLen: Cardinal; AData: PByte; begin ADataLen := MAX_CODEBIN_LEN; Result := False; if not ReadCodeAt(AnAddress, ADataLen) then exit; AData := @FCodeBin[0]; while (ADataLen > 0) and (AData^ = $90) do begin // nop inc(AData); dec(ADataLen); end; Result := ADataLen > 0; if not Result then exit; AnIsOutsideFrame := False; if AData^ = $55 then begin // push ebp AnIsOutsideFrame := True; exit; end; if AData^ = $C3 then begin // ret AnIsOutsideFrame := True; exit; end; if AData^ in [$50..$54, $56..$57] then begin // push while (ADataLen > 1) and (AData^ in [$50..$57]) do begin inc(AData); dec(ADataLen); end; if AData^ = $55 then begin // push ebp AnIsOutsideFrame := True; exit; end; //48 8D A4 24 50FBFFFF lea rsp,[rsp-$000004B0] //48 8D 64 24 C0 lea rsp,[rsp-$40] //but NOT 48 8D A4 24 B040000 lea rsp,[rsp+$000004B0] if (ADataLen >= 4) and (AData[0] = $48) and (AData[1] = $8D) and (AData[3] = $24) and ( ( (AData[2] = $64) and ((AData[4] and $80) <> 0) ) or ( (ADataLen >= 8) and (AData[2] = $A4) and ((AData[7] and $80) <> 0) ) ) then begin // mov rbp,rsp // AFTER push ebp AnIsOutsideFrame := True; exit; end; end; //if (ADataLen >= 2) and (AData[0] = $89) and (AData[1] = $E5) // 32 bit mov ebp, esp if (ADataLen >= 3) and (AData[0] = $48) and (AData[1] = $89) and (AData[2] = $E5) then begin // mov rbp,rsp // AFTER push ebp // Need 1 byte before, to check for "push ebp" exit; end; end; initialization DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} ); end.