{ $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 = (os0, os8, os16, os32, os64, os48, os80, os128, os256, os512); TAddressSize = (as16, as32, as64); TRegisterType = (regNone, regGeneral, regGeneralH {upper half of general register}, regMm, regXmm, regSegment, regControl, regDebug, regX87, regFlags, regInvalid); TModRMType = (modReg, modMem); TModRMTypes = set of TModRMType; TSimdOpcode = (soInvalid, soNone, so66, soF2, soF3); TSimdOpcodes = set of TSimdOpcode; 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_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, OPaaa, OPaad, OPaam, OPaas, OPadc, OPadcx, OPadd, OPaddsub, OPadox, OPaesdec, OPaesdec128kl, OPaesdec256kl, OPaesdeclast, OPaesdecwide128kl, OPaesdecwide256kl, OPaesenc, OPaesenc128kl, OPaesenc256kl, OPaesenclast, OPaesencwide128kl, OPaesencwide256kl, OPaesimc, OPaeskeygenassist, OPand, OPandn, OParpl, OPbextr, OPblend, OPblendv, OPblsi, OPblsmsk, OPblsr, OPbndcl, OPbndcn, OPbndcu, OPbndldx, OPbndmk, OPbndmov, OPbndstx, OPbound, OPbsf, OPbsr, OPbswap, OPbt, OPbtc, OPbtr, OPbts, OPbzhi, OPcall, OPcbw, OPcdq, OPcdqe, OPclac, OPclc, OPcld, OPcldemote, OPclflush, OPclflushopt, OPclgi, OPcli, OPclrssbsy, OPclts, OPclwb, OPcmc, OPcmov__, OPcmp, OPcmps, OPcmpxchg, OPcomi, OPcpuid, OPcqo, OPcrc32, OPcvtdq2, OPcvtpd2, OPcvtpi2, OPcvtps2, OPcvtsd2, OPcvtsi2, OPcvtss2, OPcvttpd2, OPcvttps2, OPcvttsd2, OPcvttss2, OPcwd, OPcwde, OPdaa, OPdas, OPdec, OPdiv, OPdp, OPemms, OPencls, OPenclu, OPencodekey128, OPencodekey256, OPendbr32, OPendbr64, OPenter, OPextractps, OPf2xm1, OPfabs, OPfadd, OPfbld, OPfbstp, OPfchs, OPfclex, OPfcmov__, OPfcom, OPfcos, OPfdecstp, OPfdiv, OPfdivr, OPfemms, OPffree, OPfiadd, OPficom, OPfidiv, OPfidivr, OPfild, OPfimul, OPfincstp, OPfinit, OPfist, OPfisttp, OPfisub, OPfisubr, OPfld, OPfld1, OPfldcw, OPfldenv, OPfldl2e, OPfldl2t, OPfldlg2, OPfldln2, OPfldpi, OPfldz, OPfmul, OPfnclex, OPfninit, OPfnop, OPfnsave, OPfnstcw, OPfnstenv, OPfnstsw, OPfpatan, OPfprem, OPfprem1, OPfptan, OPfrndint, OPfrstor, OPfsave, OPfscale, OPfsin, OPfsincos, OPfsqrt, OPfst, OPfstcw, OPfstenv, OPfstsw, OPfsub, OPfsubr, OPftst, OPfucom, OPfwait, OPfxam, OPfxch, OPfxrstor, OPfxsave, OPfxtract, OPfyl2x, OPfyl2xp1, OPgf2p8affineinvqb, OPgf2p8affineqb, OPgf2p8mulb, OPgetbv, OPhadd, OPhlt, OPhreset, OPhsub, OPidiv, OPimul, OPin, OPinc, OPincss, OPins, OPinsertps, OPint, OPint1, OPint3, OPinto, OPinvd, OPinvlpg, OPinvlpga, OPinvpcid, OPiret, OPj__, OPjcxz, OPjecxz, OPjmp, OPjrcxz, OPkadd, OPkand, OPkandn, OPkmov, OPknot, OPkor, OPkortest, OPkshiftl, OPkshiftr, OPktest, OPkunpckbw, OPkunpckdq, OPkunpckwd, OPkxnor, OPkxor, OPlahf, OPlar, OPlddqu, OPldmxcsr, OPlds, OPlea, OPleave, OPles, OPlfence, OPlfs, OPlgdt, OPlgs, OPlidt, OPlldt, OPlmsw, OPloadiwkey, OPlock, OPlods, OPloop, OPlsl, OPlss, OPltr, OPlzcnt, OPmaskmov, OPmax, OPmcommit, OPmfence, OPmin, OPmonitor, OPmov, OPmova, OPmovbe, OPmovddup, OPmovdir64b, OPmovdiri, OPmovdq2q, OPmovh, OPmovhlps, OPmovl, OPmovlh, OPmovmsk, OPmovnt, OPmovq2dq, OPmovs, OPmovshdup, OPmovsldup, OPmovsx, OPmovu, OPmovzx, OPmpsadbw, OPmul, OPmulx, OPmwait, OPneg, OPnop, OPnot, OPor, OPout, OPouts, OPpabs, OPpackssdw, OPpacksswb, OPpackusdw, OPpackuswb, OPpadd, OPpadds, OPpaddus, OPpalignr, OPpand, OPpandn, OPpause, OPpavg, OPpavgusb, OPpblendvb, OPpblendw, OPpclmulqdq, OPpcmpeq, OPpcmpestri, OPpcmpestrm, OPpcmpgt, OPpcmpistri, OPpcmpistrm, OPpconfig, OPpdep, OPpext, OPpextr, OPpf2id, OPpf2iw, OPpfacc, OPpfadd, OPpfcmpeq, OPpfcmpge, OPpfcmpgt, OPpfmax, OPpfmin, OPpfmul, OPpfnacc, OPpfpnacc, OPpfrcp, OPpfrcpit1, OPpfrcpit2, OPpfrsqit1, OPpfrsqrt, OPpfsub, OPpfsubr, OPphadd, OPphaddsw, OPphminposuw, OPphsub, OPphsubsw, OPpi2fd, OPpi2fw, OPpinsr, OPpmaddubsw, OPpmaddwd, OPpmaxs, OPpmaxu, OPpmins, OPpminu, OPpmovmskb, OPpmovsx, OPpmovzx, OPpmuldq, OPpmulhrsw, OPpmulhrw, OPpmulhuw, OPpmulhw, OPpmull, OPpmuludq, OPpop, OPpopa, OPpopad, OPpopcnt, OPpopf, OPpor, OPprefetch, OPpsadbw, OPpshuf, OPpsign, OPpsll, OPpsmash, OPpsra, OPpsrl, OPpsub, OPpsubs, OPpsubus, OPpswapd, OPptest, OPptwrite, OPpunpckhbw, OPpunpckhdq, OPpunpckhqdq, OPpunpckhwd, OPpunpcklbw, OPpunpckldq, OPpunpcklqdq, OPpunpcklwd, OPpush, OPpusha, OPpushf, OPpvalidate, OPpxor, OPrcl, OPrcp, OPrcr, OPrdfsbase, OPrdgsbase, OPrdmsr, OPrdpid, OPrdpkru, OPrdpmc, OPrdpru, OPrdrand, OPrdseed, OPrdss, OPrdtsc, OPrep, OPret, OPretf, OPrmpadjust, OPrmpupdate,OProl, OPror, OProrx, OPround, OPrsm, OPrsqrt, OPrstorssp, OPsahf, OPsal, OPsalc, OPsar, OPsaveprevssp, OPsbb, OPscas, OPserialize, OPset__, OPsetbv, OPsetssbsy, OPsfence, OPsgdt, OPsha1msg1, OPsha1msg2, OPsha1nexte, OPsha1rnds4, OPsha256msg1, OPsha256msg2, OPsha256rnds2, OPshl, OPshr, OPshuf, OPsidt, OPskinit, OPsldt, OPsmsw, OPsqrt, OPstac, OPstc, OPstd, OPstgi, OPsti, OPstmxcsr, OPstos, OPstr, OPsub, OPswapgs, OPsyscall, OPsysenter, OPsysexit, OPsysret, OPtest, OPtpause, OPtzcnt, OPucomi, OPud1, OPud2, OPumonitor, OPumwait, OPunpckh, OPunpckl, OPvalign, OPvblendm, OPvbroadcast, OPvcompress, OPvcvtne2ps2bf16, OPvcvtneps2bf16, OPvcvtpd2, OPvcvtph2ps, OPvcvtps2, OPvcvtqq2, OPvcvtsd2usi, OPvcvtss2usi, OPvcvttpd2, OPvcvttps2, OPvcvttsd2usi, OPvcvttss2usi, OPvcvtudq2, OPvcvtuqq2, OPvcvtusi2, OPvdbpsadbw, OPvdpbf16ps, OPverr, OPverw, OPvexpand, OPvextract, OPvfixupimm, OPvfmadd132, OPvfmadd213, OPvfmadd231, OPvfmaddsub132, OPvfmaddsub213, OPvfmaddsub231, OPvfmsub132, OPvfmsub213, OPvfmsub231, OPvfmsubadd132, OPvfmsubadd213, OPvfmsubadd231, OPvfnmadd132, OPvfnmadd213, OPvfnmadd231, OPvfnmsub132, OPvfnmsub213, OPvfnmsub231, OPvfpclass, OPvgatherd, OPvgatherq, OPvgetexp, OPvgetmant, OPvinsert, OPvmaskmov, OPvmcall, OPvmclear, OPvmfunc, OPvmgexit, OPvmlaunch, OPvmload, OPvmmcall, OPvmptrld, OPvmptrst, OPvmread, OPvmresume, OPvmrun, OPvmsave, OPvmwrite, OPvmxoff, OPvmxon, OPvp2intersect, OPvpblendd, OPvpblendm, OPvpbroadcast, OPvpbroadcastm, OPvpcmp, OPvpcmpu, OPvpcompress, OPvpconflict, OPvpdpbusd, OPvpdpbusds, OPvpdpwssd, OPvpdpwssds, OPvperm, OPvperm2, OPvpermi2, OPvpermil, OPvpermt2, OPvpexpand,OPvpgather, OPvplzcnt, OPvpmadd52huq, OPvpmadd52luq, OPvpmaskmov, OPvpmovb2m, OPvpmovd, OPvpmovd2m, OPvpmovm2, OPvpmovq, OPvpmovq2m, OPvpmovsd, OPvpmovsq, OPvpmovswb, OPvpmovusd, OPvpmovusq, OPvpmovuswb, OPvpmovw2m, OPvpmovwb, OPvpmultishiftqb, OPvpopcnt, OPvprol, OPvprolv, OPvpror, OPvprorv, OPvpscatter, OPvpshld, OPvpshldv, OPvpshrd, OPvpshrdv, OPvpshufbitqmb, OPvpsllv, OPvpsrav, OPvpsrlv, OPvpternlog, OPvptestm, OPvptestnm, OPvrange, OPvrcp14, OPvreduce, OPvrndscale, OPvrsqrt14, OPvscalef, OPvscatterd, OPvscatterq, OPvshuf, OPvtest, OPvzeroall, OPvzeroupper, OPwbinvd, OPwbnoinvd, OPwrfsbase, OPwrgsbase, OPwrmsr, OPwrpkru, OPwrss, OPwruss, OPxabort, OPxacquire, OPxadd, OPxbegin, OPxchg, OPxend, OPxgetbv, OPxlat, OPxor, OPxrelease, OPxrstor, OPxrstors, OPxsave, OPxsavec, OPxsaveopt, OPxsaves, OPxsetbv, OPxtest ); TOpCodeSuffix = ( OPSnone, // Condition OPSc_o, OPSc_no, OPSc_b, OPSc_nb, OPSc_z, OPSc_nz, OPSc_be, OPSc_nbe, OPSc_s, OPSc_ns, OPSc_p, OPSc_np, OPSc_l, OPSc_nl, OPSc_le, OPSc_nle, OPSc_e, OPSc_ne, OPSc_u, OPSc_nu, // Prefetch OPSp_t0, OPSp_t1, OPSp_t2, OPSp_nta, OPSp_w, // Generic size OPSx_8b, OPSx_16b, OPSx_b, OPSx_d, OPSx_dd, OPSx_dq, OPSx_dqa, OPSx_dqa32, OPSx_dqa64, OPSx_dqu, OPSx_dqu8, OPSx_dqu16, OPSx_dqu32, OPSx_dqu64, OPSx_f32x4, OPSx_f32x8, OPSx_f64x2, OPSx_f64x4, OPSx_f128, OPSx_hw, OPSx_i, OPSx_i32x4, OPSx_i32x8, OPSx_i64x2, OPSx_i64x4, OPSx_i128, OPSx_ip, OPSx_lw, OPSx_p, OPSx_pd, OPSx_ph, OPSx_pi, OPSx_pp, OPSx_pq, OPSx_ps, OPSx_q, OPSx_qd, OPSx_qq, OPSx_sd, OPSx_si, OPSx_ss, OPSx_udq, OPSx_uqq, OPSx_w, OPSx_x ); TFullOpcode = record //Prefix: Opcode: TOpcode; Suffix: TOpCodeSuffix; end; TOperandFlag = (ofMemory); TOperandFlags = set of TOperandFlag; TInstruction = record OpCode: TFullOpcode; 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; ModRM: record Mode: Byte; Index: Byte; RM: Byte; end; //--- 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 AddEv; procedure AddEw; procedure AddEy; procedure AddFv; procedure AddGb; procedure AddGd; procedure AddGv; procedure AddGw; procedure AddGy; 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 AddMp; procedure AddMq; procedure AddMs; procedure AddMw_Rv; procedure AddMy; procedure AddNq; procedure AddOb; procedure AddOv; procedure AddPq; procedure AddPy; procedure AddQd; procedure AddQq; procedure AddRd_q; procedure AddRy; procedure AddSw; procedure AddUdq; procedure AddUpd; procedure AddUps; procedure AddUq; procedure AddVdq; procedure AddVpd; procedure AddVps; procedure AddVq; procedure AddVsd; procedure AddVss; procedure AddVy; 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 AddReg(AType: TRegisterType; ASize: TOperandSize; AIndex: Byte); 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 Check32; procedure Check64; procedure CheckLock; procedure CheckRepeat; procedure CheckRepeatX; procedure ClearSIMDPrefix; procedure DecodeSIMD(AClearPrefix: Boolean = False; AValidClear: TSimdOpcodes = [soNone, so66, soF2, soF3]); procedure DecodeModRM; 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 AddressSize: TAddressSize; procedure SetOpcode(AOpcode: TOpcode; ASuffix: TOpCodeSuffix = OPSnone); procedure Default64; procedure Force64; function Ignore64(s: String): String; function OperandSize: TOperandSize; function StdCond(AIndex: Byte): TOpCodeSuffix; function RegName(AType: TRegisterType; ASize: TOperandSize; 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 = (0, 1, 2, 4, 8, 6, 10, 16, 32, 64); OPERAND_BITS: array[TOperandSize] of Word = (0, 8, 16, 32, 64, 48, 80, 128, 256, 512); ADDRESS_SIZE: array[TAddressSize] of TOperandSize = (os16, os32, os64); REXOFFSET: array[Boolean] of Byte = (0, 8); MODE_SIZE: array[TFPDMode] of TOperandSize = (os32, os64); (* // 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!', '**group11**', '!group11!', '**group12**', '!group12!', '**group13**', '!group13!', '**group14**', '!group14!', '**group15**', '!group15!', '**group16**', '!group16!', '**groupp**', '!groupp!', 'aaa', 'aad', 'aam', 'aas', 'adc', 'adcx', 'add', 'addsub', 'adox', 'aesdec', 'aesdec128kl', 'aesdec256kl', 'aesdeclast', 'aesdecwide128kl', 'aesdecwide256kl', 'aesenc', 'aesenc128kl', 'aesenc256kl', 'aesenclast', 'aesencwide128kl', 'aesencwide256kl', 'aesimc', 'aeskeygenassist', 'and', 'andn', 'arpl', 'bextr', 'blend', 'blendv', 'blsi', 'blsmsk', 'blsr', 'bndcl', 'bndcn', 'bndcu', 'bndldx', 'bndmk', 'bndmov', 'bndstx', 'bound', 'bsf', 'bsr', 'bswap', 'bt', 'btc', 'btr', 'bts', 'bzhi', 'call', 'cbw', 'cdq', 'cdqe', 'clac', 'clc', 'cld', 'cldemote', 'clflush', 'clflushopt', 'clgi', 'cli', 'clrssbsy', 'clts', 'clwb', 'cmc', 'cmov', 'cmp', 'cmps', 'cmpxchg', 'comi', 'cpuid', 'cqo', 'crc32', 'cvtdq2', 'cvtpd2', 'cvtpi2', 'cvtps2', 'cvtsd2', 'cvtsi2', 'cvtss2', 'cvttpd2', 'cvttps2', 'cvttsd2','cvttss2', 'cwd', 'cwde', 'daa', 'das', 'dec', 'div', 'dp', 'emms', 'encls', 'enclu', 'encodekey128', 'encodekey256', 'endbr32', 'endbr64', 'enter', 'extractps', 'f2xm1', 'fabs', 'fadd', 'fbld', 'fbstp', 'fchs', 'fclex', 'fcmov', 'fcom', 'fcos', 'fdecstp', 'fdiv', 'fdivr', 'femms', 'ffree', 'fiadd', 'ficom', 'fidiv', 'fidivr', 'fild', 'fimul', 'fincstp', 'finit', 'fist', 'fisttp', 'fisub', 'fisubr', 'fld', 'fld1', 'fldcw', 'fldenv', 'fldl2e', 'fldl2t', 'fldlg2', 'fldln2', 'fldpi', 'fldz', 'fmul', 'fnclex', 'fninit', 'fnop', 'fnsave', 'fnstcw', 'fnstenv', 'fnstsw', 'fpatan', 'fprem', 'fprem1', 'fptan', 'frndint', 'frstor', 'fsave', 'fscale', 'fsin', 'fsincos', 'fsqrt', 'fst', 'fstcw', 'fstenv', 'fstsw', 'fsub', 'fsubr', 'ftst', 'fucom', 'fwait', 'fxam', 'fxch', 'fxrstor', 'fxsave', 'fxtract', 'fyl2x', 'fyl2xp1', 'gf2p8affineinvqb', 'gf2p8affineqb', 'gf2p8mulb', 'getbv', 'hadd', 'hlt', 'hreset', 'hsub', 'idiv', 'imul', 'in', 'inc', 'incss', 'ins', 'insertps', 'int', 'int1', 'int3', 'into', 'invd', 'invlpg', 'invlpga', 'invpcid', 'iret', 'j', 'jcxz', 'jecxz', 'jmp', 'jrcxz', 'kadd', 'kand', 'kandn', 'kmov', 'knot', 'kor', 'kortest', 'kshiftl', 'kshiftr', 'ktest', 'kunpckbw', 'kunpckdq', 'kunpckwd', 'kxnor', 'kxor', 'lahf', 'lar', 'lddqu', 'ldmxcsr', 'lds', 'lea', 'leave', 'les', 'lfence', 'lfs', 'lgdt', 'lgs', 'lidt', 'lldt', 'lmsw', 'loadiwkey', 'lock', 'lods', 'loop', 'lsl', 'lss', 'ltr', 'lzcnt', 'maskmov', 'max', 'mcommit', 'mfence', 'min', 'monitor', 'mov', 'mova', 'movbe', 'movddup', 'movdir64b', 'movdiri', 'movdq2q', 'movh', 'movhlps', 'movl', 'movlh', 'movmsk', 'movnt', 'movq2dq', 'movs', 'movshdup', 'movsldup', 'movsx', 'movu', 'movzx', 'mpsadbw', 'mul', 'mulx', 'mwait', 'neg', 'nop', 'not', 'or', 'out', 'outs', 'pabs', 'packssdw', 'packsswb', 'packusdw', 'packuswb', 'padd', 'padds', 'paddus', 'palignr', 'pand', 'pandn', 'pause', 'pavg', 'pavgusb', 'pblendvb', 'pblendw', 'pclmulqdq', 'pcmpeq', 'pcmpestri', 'pcmpestrm', 'pcmpgt', 'pcmpistri', 'pcmpistrm', 'pconfig', 'pdep', 'pext', 'pextr', 'pf2id', 'pf2iw', 'pfacc', 'pfadd', 'pfcmpeq', 'pfcmpge', 'pfcmpgt', 'pfmax', 'pfmin', 'pfmul', 'pfnacc', 'pfpnacc', 'pfrcp', 'pfrcpit1', 'pfrcpit2', 'pfrsqit1', 'pfrsqrt', 'pfsub', 'pfsubr', 'phadd', 'phaddsw', 'phminposuw', 'phsub', 'phsubsw', 'pi2fd', 'pi2fw', 'pinsr', 'pmaddubsw', 'pmaddwd', 'pmaxs', 'pmaxu', 'pmins', 'pminu', 'pmovmskb', 'pmovsx', 'pmovzx', 'pmuldq', 'pmulhrsw', 'pmulhrw', 'pmulhuw', 'pmulhw', 'pmull', 'pmuludq', 'pop', 'popa', 'popad', 'popcnt', 'popf', 'por', 'prefetch', 'psadbw', 'pshuf', 'psign', 'psll', 'psmash', 'psra', 'psrl', 'psub', 'psubs', 'psubus', 'pswapd', 'ptest', 'ptwrite', 'punpckhbw', 'punpckhdq', 'punpckhqdq', 'punpckhwd', 'punpcklbw', 'punpckldq', 'punpcklqdq', 'punpcklwd', 'push', 'pusha', 'pushf', 'pvalidate', 'pxor', 'rcl', 'rcp', 'rcr', 'rdfsbase', 'rdgsbase', 'rdmsr', 'rdpid', 'rdpkru', 'rdpmc', 'rdpru', 'rdrand', 'rdseed', 'rdss', 'rdtsc', 'rep', 'ret', 'retf', 'rmpadjust', 'rmpupdate','rol', 'ror', 'rorx', 'round', 'rsm', 'rsqrt', 'rstorssp', 'sahf', 'sal', 'salc', 'sar', 'saveprevssp', 'sbb', 'scas', 'serialize', 'set', 'setbv', 'setssbsy', 'sfence', 'sgdt', 'sha1msg1', 'sha1msg2', 'sha1nexte', 'sha1rnds4', 'sha256msg1', 'sha256msg2', 'sha256rnds2', 'shl', 'shr', 'shuf', 'sidt', 'skinit', 'sldt', 'smsw', 'sqrt', 'stac', 'stc', 'std', 'stgi', 'sti', 'stmxcsr', 'stos', 'str', 'sub', 'swapgs', 'syscall', 'sysenter', 'sysexit', 'sysret', 'test', 'tpause', 'tzcnt', 'ucomi', 'ud1', 'ud2', 'umonitor', 'umwait', 'unpckh', 'unpckl', 'valign', 'vblendm', 'vbroadcast', 'vcompress', 'vcvtne2ps2bf16', 'vcvtneps2bf16', 'vcvtpd2', 'vcvtph2ps', 'vcvtps2', 'vcvtqq2', 'vcvtsd2usi', 'vcvtss2usi', 'vcvttpd2', 'vcvttps2', 'vcvttsd2usi', 'vcvttss2usi', 'vcvtudq2', 'vcvtuqq2', 'vcvtusi2', 'vdbpsadbw', 'vdpbf16ps', 'verr', 'verw', 'vexpand', 'vextract', 'vfixupimm', 'vfmadd132', 'vfmadd213', 'vfmadd231', 'vfmaddsub132', 'vfmaddsub213', 'vfmaddsub231', 'vfmsub132', 'vfmsub213', 'vfmsub231', 'vfmsubadd132', 'vfmsubadd213', 'vfmsubadd231', 'vfnmadd132', 'vfnmadd213', 'vfnmadd231', 'vfnmsub132', 'vfnmsub213', 'vfnmsub231', 'vfpclass', 'vgatherd', 'vgatherq', 'vgetexp', 'vgetmant', 'vinsert', 'vmaskmov', 'vmcall', 'vmclear', 'vmfunc', 'vmgexit', 'vmlaunch', 'vmload', 'vmmcall', 'vmptrld', 'vmptrst', 'vmread', 'vmresume', 'vmrun', 'vmsave', 'vmwrite', 'vmxoff', 'vmxon', 'vp2intersect', 'vpblendd', 'vpblendm', 'vpbroadcast', 'vpbroadcastm', 'vpcmp', 'vpcmpu', 'vpcompress', 'vpconflict', 'vpdpbusd', 'vpdpbusds', 'vpdpwssd', 'vpdpwssds', 'vperm', 'vperm2', 'vpermi2', 'vpermil', 'vpermt2', 'vpexpand','vpgather', 'vplzcnt', 'vpmadd52huq', 'vpmadd52luq', 'vpmaskmov', 'vpmovb2m', 'vpmovd', 'vpmovd2m', 'vpmovm2', 'vpmovq', 'vpmovq2m', 'vpmovsd', 'vpmovsq', 'vpmovswb', 'vpmovusd', 'vpmovusq', 'vpmovuswb', 'vpmovw2m', 'vpmovwb', 'vpmultishiftqb', 'vpopcnt', 'vprol', 'vprolv', 'vpror', 'vprorv', 'vpscatter', 'vpshld', 'vpshldv', 'vpshrd', 'vpshrdv', 'vpshufbitqmb', 'vpsllv', 'vpsrav', 'vpsrlv', 'vpternlog', 'vptestm', 'vptestnm', 'vrange', 'vrcp14', 'vreduce', 'vrndscale', 'vrsqrt14', 'vscalef', 'vscatterd', 'vscatterq', 'vshuf', 'vtest', 'vzeroall', 'vzeroupper', 'wbinvd', 'wbnoinvd', 'wrfsbase', 'wrgsbase', 'wrmsr', 'wrpkru', 'wrss', 'wruss', 'xabort', 'xacquire', 'xadd', 'xbegin', 'xchg', 'xend', 'xgetbv', 'xlat', 'xor', 'xrelease', 'xrstor', 'xrstors', 'xsave', 'xsavec', 'xsaveopt', 'xsaves', 'xsetbv', 'xtest' ); OPCODE_SUFFIX_NAME: array [TOpCodeSuffix] of String = ( '', 'o', 'no', 'b', 'nb', 'z', 'nz', 'be', 'nbe', 's', 'ns', 'p', 'np', 'l', 'nl', 'le', 'nle', 'e', 'ne', 'u', 'nu', 't0', 't1', 't2', 'nta', 'w', '8b', '16b', 'b', 'd', 'dd', 'dq', 'dqa', 'dqa32', 'dqa64', 'dqu', 'dqu8', 'dqu16', 'dqu32', 'dqu64', 'f32x4', 'f32x8', 'f64x2', 'f64x4', 'f128', 'hw', 'i', 'i32x4', 'i32x8', 'i64x2', 'i64x4', 'i128', 'ip', 'lw', 'p', 'pd', 'ph', 'pi', 'pp', 'pq', 'ps', 'q', 'qd', 'qq', 'sd', 'si', 'ss', 'udq', 'uqq', 'w', 'x' ); operator = (Left, Right: TFullOpcode): Boolean; begin Result := (Left.Opcode = Right.Opcode) and (Left.Suffix = Right.Suffix); end; { 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.DecodeSIMD(AClearPrefix: Boolean; AValidClear: TSimdOpcodes); 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; if AClearPrefix and (SimdOpcode in AValidClear) then Flags := Flags - [pre66, preF3, preF2]; end; procedure TX86Disassembler.DecodeModRM; begin Include(Flags, flagModRM); ModRM.Mode := (Code[ModRMIdx] shr 6) and 3; ModRM.Index := (Code[ModRMIdx] shr 3) and 7; ModRM.RM := (Code[ModRMIdx] ) and 7; end; procedure TX86Disassembler.ClearSIMDPrefix; begin Flags := Flags - [pre66, preF2, preF3]; end; procedure TX86Disassembler.SetOpcode(AOpcode: TOpcode; ASuffix: TOpCodeSuffix); begin Instruction^.OpCode.Opcode := AOpcode; Instruction^.OpCode.Suffix := ASuffix; end; function TX86Disassembler.AddressSize: 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.StdCond(AIndex: Byte): TOpCodeSuffix; const COND: array[0..$F] of TOpCodeSuffix = ( OPSc_o, OPSc_no, OPSc_b, OPSc_nb, OPSc_z, OPSc_nz, OPSc_be, OPSc_nbe, OPSc_s, OPSc_ns, OPSc_p, OPSc_np, OPSc_l, OPSc_nl, OPSc_le, OPSc_nle ); begin Result := COND[AIndex and $F]; end; function TX86Disassembler.RegName(AType: TRegisterType; ASize: TOperandSize; AIndex: Byte): String; const REGS: array[0..7] of string = ('ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di'); REG8: array[0..7] of String = ('a', 'c', 'd', 'b', 'sp', 'bp', 'si', 'di'); SREG: array[0..5] of String = ('es', 'cs', 'ss', 'ds', 'fs', 'gs'); begin case AType of regNone: begin Result := ''; end; regGeneral: begin case ASize of os8: begin if AIndex <= High(REG8) then Result := REG8[AIndex] + 'l' else Result := Format('r%ub', [AIndex]); end; os16: begin if AIndex <= High(REG8) then Result := REGS[AIndex] else Result := Format('r%uw', [AIndex]); end; os32: begin if AIndex <= High(REG8) then Result := 'e' + REGS[AIndex] else Result := Format('r%ud', [AIndex]); end; os64: begin if AIndex <= High(REG8) then Result := 'r' + REGS[AIndex] else Result := Format('r%u', [AIndex]); end; else Result := Format('*r%u.%u', [AIndex, OPERAND_BITS[ASize]]); end; end; regGeneralH: begin case ASize of os8: begin if AIndex <= 3 then Result := REG8[AIndex] + 'h' else Result := Format('*r%uh', [AIndex]); end; else Result := Format('*r%uh.%u', [AIndex, OPERAND_BITS[ASize]]); end; end; regMm: begin Result := Format('mm%u', [AIndex]); end; regXmm: begin case ASize of os32, os64, os128: begin Result := Format('xmm%u', [AIndex]); end; os256: begin Result := Format('ymm%u', [AIndex]); end; os512: begin Result := Format('zmm%u', [AIndex]); end; else Result := Format('*mm%u.%u', [AIndex, OPERAND_BITS[ASize]]); end; end; regSegment: begin if AIndex <= High(SREG) then Result := SREG[AIndex] else Result := Format('*s%u', [AIndex]); end; regControl: begin Result := Format('cr%u', [AIndex]); end; regDebug: begin Result := Format('dr%u', [AIndex]); end; regX87: begin Result := Format('st(%u)', [AIndex]); end; regFlags: begin case ASize of os16: Result := 'flags'; os32: Result := 'eflags'; os64: Result := 'rflags'; else Result := Format('*flags.%u', [OPERAND_BITS[ASize]]); end; end; else Result := Format('**%u', [AIndex]); end; end; procedure TX86Disassembler.AddReg(AType: TRegisterType; ASize: TOperandSize; AIndex: Byte); begin if not (flagRex in Flags) and (AType = regGeneral) and (ASize = os8) and (AIndex >= 4) then begin // in 'legacy' mode the 8 bit registers are encoded as // AL, CL, DL, BL, AH, CH, DH, BH // in 'extended' mode the 8 bit registers are encoded as // AL, CL, DL, BL, SP, BP, SI, DI // // The 8 bit general purpose 8 bit default to the 'extended' registers // So for 'legacy' mode we change the type and adjust the offset AddOperand(RegName(regGeneralH, ASize, AIndex - 4), ASize) end else AddOperand(RegName(AType, ASize, AIndex + REXOFFSET[rexB in Flags]), ASize); end; procedure TX86Disassembler.AddModReg(AType: TRegisterType; ASize: TOperandSize); begin DecodeModRM; if not (flagRex in Flags) and (AType = regGeneral) and (ASize = os8) and (ModRM.Index >= 4) then begin // in 'legacy' mode the 8 bit registers are encoded as // AL, CL, DL, BL, AH, CH, DH, BH // in 'extended' mode the 8 bit registers are encoded as // AL, CL, DL, BL, SP, BP, SI, DI // // The 8 bit general purpose 8 bit default to the 'extended' registers // So for 'legacy' mode we change the type and adjust the offset AddOperand(RegName(regGeneralH, ASize, ModRM.Index - 4), ASize) end else AddOperand(RegName(AType, ASize, ModRM.Index + REXOFFSET[rexR in Flags]), ASize); end; procedure TX86Disassembler.AddModRM(AReqTypes: TModRMTypes; ASize: TOperandSize; AType: TRegisterType); procedure Mem16; const REGS16: array[0..7] of string = ('bx+si', 'bx+di', 'bp+si', 'bp+di', 'si', 'di', 'bp', 'bx'); begin case ModRM.Mode of 0: begin if ModRM.RM = 6 // disp16 -> exception to the regs then AddOperand('%s', ASize, 2, [hvfSigned, hvfIncludeHexchar], [ofMemory]) else AddOperand(REGS16[ModRM.RM], ASize, 0, [], [ofMemory]); end; 1: AddOperand(REGS16[ModRM.RM] + '%s', ASize, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]); 2: AddOperand(REGS16[ModRM.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 DecodeModRM; // Check for reg (ProcessMode = 3) first; if ModRM.Mode = 3 then begin if modReg in AReqTypes then AddReg(AType, ASize, ModRM.RM) else AddReg(regInvalid, ASize, ModRM.RM); Exit; end; // Check if mem is allowed if not (modMem in AReqTypes) then begin AddOperand(RegName(regInvalid, ASize, 0), OPERAND_BYTES[ASize], [], [ofMemory]); Exit; end; Oper.Size := 0; Oper.Flags := []; Oper.Value := ''; // Here only mem access AddrSize := AddressSize; if AddrSize = as16 then begin Mem16; Exit; end; if ModRM.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 (ModRM.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 := RegName(regGeneral, ADDRESS_SIZE[AddrSize], sib.Base + REXOFFSET[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 := RegName(regGeneral, ADDRESS_SIZE[AddrSize], sib.Index + REXOFFSET[rexX in Flags]) + Oper.Value end; end else begin // no sib Oper.Value := RegName(regGeneral, ADDRESS_SIZE[AddrSize], ModRM.RM + REXOFFSET[rexB in Flags]); end; case ModRM.Mode of 0: begin // exceptions to std encoding if ModRM.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, MODE_SIZE[ProcessMode]); end; procedure TX86Disassembler.AddDd_q; begin AddModReg(regDebug, MODE_SIZE[ProcessMode]); end; procedure TX86Disassembler.AddEb; begin AddModRM([modReg, modMem], os8, regGeneral); end; procedure TX86Disassembler.AddEd; begin AddModRM([modReg, modMem], os32, regGeneral); end; procedure TX86Disassembler.AddEv; begin AddModRM([modReg, modMem], OperandSize, regGeneral); end; procedure TX86Disassembler.AddEw; begin AddModRM([modReg, modMem], os16, regGeneral); end; procedure TX86Disassembler.AddEy; begin if OperandSize = os64 then AddModRM([modReg, modMem], os64, regGeneral) else AddModRM([modReg, modMem], os32, regGeneral); end; procedure TX86Disassembler.AddFv; begin AddReg(regFlags, OperandSize, 0); end; procedure TX86Disassembler.AddGb; begin AddModReg(regGeneral, os8); end; procedure TX86Disassembler.AddGd; begin AddModReg(regGeneral, os32); end; procedure TX86Disassembler.AddGv; begin AddModReg(regGeneral, OperandSize); end; procedure TX86Disassembler.AddGw; begin AddModReg(regGeneral, os16); end; procedure TX86Disassembler.AddGy; begin if OperandSize = os64 then AddModReg(regGeneral, os64) else AddModReg(regGeneral, os32); end; procedure TX86Disassembler.AddGz; begin if OperandSize = os16 then AddModReg(regGeneral, os16) else AddModReg(regGeneral, os32); 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, regNone); end; procedure TX86Disassembler.AddMa; begin AddModRM([modMem], OperandSize, regNone); end; procedure TX86Disassembler.AddMb; begin AddModRM([modMem], os8, regNone); end; procedure TX86Disassembler.AddMd; begin AddModRM([modMem], os32, regNone); end; procedure TX86Disassembler.AddMdq; begin AddModRM([modMem], os128, regNone) end; procedure TX86Disassembler.AddMp; begin if OperandSize = os16 //XXXX:XXXX then AddModRM([modMem], os32, regNone) else AddModRM([modMem], os48, regNone); end; procedure TX86Disassembler.AddMq; begin AddModRM([modMem], os64, regNone); end; procedure TX86Disassembler.AddMs; begin if (ProcessMode = dm64) then AddModRM([modMem], os80, regNone) else AddModRM([modMem], os48, regNone); end; procedure TX86Disassembler.AddMw_Rv; begin DecodeModRM; if ModRM.Mode = 3 // reg then AddModRM([modReg], OperandSize, regGeneral) else AddModRM([modMem], os16, regNone); end; procedure TX86Disassembler.AddMy; begin if OperandSize = os64 then AddModRM([modMem], os64, regNone) else AddModRM([modMem], os32, regNone); end; procedure TX86Disassembler.AddNq; begin AddModRM([modReg], os64, regMm); end; procedure TX86Disassembler.AddOb; begin AddOperand('%s', os8, ADDRESS_BYTES[AddressSize], [hvfIncludeHexchar], [ofMemory]) end; procedure TX86Disassembler.AddOv; begin AddOperand('%s', ADDRESS_BYTES[AddressSize], [hvfIncludeHexchar], [ofMemory]) end; procedure TX86Disassembler.AddPy; begin if OperandSize = os64 then AddModReg(regMm, os64) else AddModReg(regMm, os32); end; procedure TX86Disassembler.AddPq; begin AddModReg(regMm, os64); end; procedure TX86Disassembler.AddQd; begin AddModRM([modReg, modMem], os32, regMm); end; procedure TX86Disassembler.AddQq; begin AddModRM([modReg, modMem], os64, regMm); end; procedure TX86Disassembler.AddRd_q; begin if (ProcessMode = dm64) then AddModRM([modReg], os64, regGeneral) else AddModRM([modReg], os32, regGeneral); end; procedure TX86Disassembler.AddRy; begin AddModRM([modReg], OperandSize, regGeneral); end; procedure TX86Disassembler.AddSw; begin AddModReg(regSegment, os16); end; procedure TX86Disassembler.AddUdq; begin AddModRM([modReg], os128, regXmm); end; procedure TX86Disassembler.AddUpd; begin AddModRM([modReg], os128, regXmm); end; procedure TX86Disassembler.AddUps; begin AddModRM([modReg], os128, regXmm); end; procedure TX86Disassembler.AddUq; begin AddModRM([modReg], os64, regXmm); end; procedure TX86Disassembler.AddVdq; begin AddModReg(regXmm, os128); 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.AddVy; begin if OperandSize = os64 then AddModReg(regXmm, os64) else AddModReg(regXmm, os32); 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 AddReg(regGeneral, os8, 0); AddIb; end; 5: begin AddReg(regGeneral, OperandSize, 0); AddIz; end; else AddOperand('!!'); end; end; procedure TX86Disassembler.DoX87; procedure AddMem14_28Env; begin AddModRM([modMem], OperandSize, regNone); end; procedure AddMem98_108Env; begin AddModRM([modMem], OperandSize, regNone); end; procedure AddMem16; begin AddModRM([modMem], os16, regNone); end; procedure AddMem32; begin AddModRM([modMem], os32, regNone); end; procedure AddMem64; begin AddModRM([modMem], os64, regNone); end; procedure AddMem80; begin AddModRM([modMem], os80, regNone); end; procedure AddReg0; begin AddReg(regX87, os80, 0); end; procedure AddRegN; begin AddReg(regX87, os80, ModRM.RM); end; procedure DoD8; const OPC: array[0..7] of TOpCode = (OPfadd, OPfmul, OPfcom, OPfcom, OPfsub, OPfsubr, OPfdiv, OPfdivr); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSnone, OPSnone, OPSnone); begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); case Code[ModRMIdx] of $00..$BF: AddMem32 else AddReg0; AddRegN; end; end; procedure DoD9; const OPC: array[0..7] of TOpCode = (OPfld, OPfxch, OPfst, OPfst, OPfldenv, OPfldcw, OPfnstenv, OPfnstcw); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSnone, OPSnone, OPSnone); 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 Code[ModRMIdx] of $00..$BF: begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); case ModRM.Index of 0, 2, 3: AddMem32; 1: SetOpcode(OPX_InvalidX87); 4, 6: AddMem14_28Env; 5, 7: AddMem16; end; end; $C0..$CF: begin SetOpcode(OPC[ModRM.Index]); AddReg0; AddRegN; end; $D0: begin SetOpcode(OPnop); end; $D8..$DF: begin SetOpcode(OPX_ReservedX87); end; $E0..$FF: begin SetOpcode(OPCx[Code[ModRMIdx] and $1F]); end; else SetOpcode(OPX_InvalidX87); end; end; procedure DoDA; const OPC: array[0..7] of TOpCode = (OPfiadd, OPfimul, OPficom, OPficom, OPfisub, OPfisubr, OPfidiv, OPfidivr); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSnone, OPSnone, OPSnone); begin case Code[ModRMIdx] of $00..$BF: begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); AddMem32; end; $C0..$C7: begin SetOpcode(OPfcmov__, OPSc_b); AddReg0; AddRegN; end; $C8..$CF: begin SetOpcode(OPfcmov__, OPSc_e); AddReg0; AddRegN; end; $D0..$D7: begin SetOpcode(OPfcmov__, OPSc_be); AddReg0; AddRegN; end; $D8..$DF: begin SetOpcode(OPfcmov__, OPSc_u); AddReg0; AddRegN; end; $E9: begin SetOpcode(OPfucom, OPSx_p); end; else SetOpcode(OPX_InvalidX87); end; end; procedure DoDB; const OPC: array[0..7] of TOpCode = (OPfild, OPfisttp, OPfist, OPfist, OPX_InvalidX87, OPfld, OPX_InvalidX87, OPfst); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSnone, OPSnone, OPSx_p); begin case Code[ModRMIdx] of $00..$BF: begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); case ModRM.Index of 0..3: AddMem32; 5, 7: AddMem80; end; end; $C0..$DF, $E8..$F7: begin case ModRM.Index of 0: SetOpcode(OPfcmov__, OPSc_nb ); 1: SetOpcode(OPfcmov__, OPSc_ne ); 2: SetOpcode(OPfcmov__, OPSc_nbe); 3: SetOpcode(OPfcmov__, OPSc_nu ); 5: SetOpcode(OPfucom, OPSx_i ); 6: SetOpcode(OPfcom, OPSx_i ); else SetOpcode(OPX_InvalidX87); end; AddReg0; AddRegN; end; $E0..$E1: begin SetOpcode(OPX_ReservedX87); end; $E2: begin SetOpcode(OPfnclex); end; $E3: begin SetOpcode(OPfninit); end; $E4: begin SetOpcode(OPX_ReservedX87); end; else SetOpcode(OPX_InvalidX87); end; end; procedure DoDC; const OPC: array[0..7] of TOpCode = (OPfadd, OPfmul, OPfcom, OPfcom, OPfsub, OPfsubr, OPfdiv, OPfdivr); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSnone, OPSnone, OPSnone); OPCx: array[0..7] of TOpCode = (OPfadd, OPfmul, OPX_InvalidX87, OPX_InvalidX87, OPfsubr, OPfsub, OPfdivr, OPfdiv); begin case Code[ModRMIdx] of $00..$BF: begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); AddMem64; end; $C0..$CF, $E0..$FF: begin SetOpcode(OPCx[ModRM.Index]); AddRegN; AddReg0; end; else SetOpcode(OPX_ReservedX87); end; end; procedure DoDD; const OPC: array[0..7] of TOpCode = (OPfld, OPfisttp, OPfst, OPfst, OPfrstor, OPX_InvalidX87, OPfnsave, OPfnstsw); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSnone, OPSnone, OPSnone); OPCx: array[0..7] of TOpCode = (OPffree, OPX_InvalidX87, OPfst, OPfst, OPX_InvalidX87, OPfucom, OPX_InvalidX87, OPX_InvalidX87); OPSx: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSx_p, OPSnone, OPSnone); begin case Code[ModRMIdx] of $00..$BF: begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); case ModRM.Index of 0..3: begin AddMem64; end; 4, 6: begin AddMem98_108Env; end; 7: begin AddMem16; end; end; end; $C0..$C7, $D0..$DF, $E8..$EF: begin SetOpcode(OPCx[ModRM.Index], OPSx[ModRM.Index]); AddRegN; end; $E0..$E7: begin SetOpcode(OPCx[ModRM.Index], OPSx[ModRM.Index]); AddRegN; AddReg0; end; $C8..$CF: SetOpcode(OPX_ReservedX87); else SetOpcode(OPX_InvalidX87); end; end; procedure DoDE; const OPC: array[0..7] of TOpCode = (OPfiadd, OPfimul, OPficom, OPficom, OPfisub, OPfisubr, OPfidiv, OPfidivr); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSnone, OPSnone, OPSnone); OPCx: array[0..7] of TOpCode = (OPfadd, OPfmul, OPX_InvalidX87, OPX_InvalidX87, OPfsubr, OPfsub, OPfdivr, OPfdiv); OPSx: array[0..7] of TOpCodeSuffix = (OPSx_p, OPSx_p, OPSnone, OPSnone, OPSx_p, OPSx_p, OPSx_p, OPSx_p); begin case Code[ModRMIdx] of $00..$BF: begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); AddMem16; end; $C0..$CF, $E0..$FF: begin SetOpcode(OPCx[ModRM.Index],OPSx[ModRM.Index]); AddRegN; AddReg0; end; $D9: begin SetOpcode(OPfcom, OPSx_pp); end; $D0..$D7: begin SetOpcode(OPX_ReservedX87); end; else SetOpcode(OPX_InvalidX87); end; end; procedure DoDF; const OPC: array[0..7] of TOpCode = (OPfild, OPfisttp, OPfist, OPfist, OPfbld, OPfild, OPfbstp, OPfist); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSnone, OPSx_p, OPSnone, OPSnone, OPSnone, OPSx_p); begin case Code[ModRMIdx] of $00..$BF: begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); case ModRM.Index of 0..3: begin AddMem16; end; 4, 6: begin AddMem80; end; 5, 7: begin AddMem64; end; end; end; $E0: begin SetOpcode(OPfnstsw); AddOperand('ax', os16); end; $E8..$EF: begin SetOpcode(OPfucom, OPSx_ip); AddReg0; AddRegN; end; $F0..$F7: begin SetOpcode(OPfcom, OPSx_ip); AddReg0; AddRegN; end; $C0..$DF: begin SetOpcode(OPX_ReservedX87); end; else SetOpcode(OPX_InvalidX87); end; end; begin DecodeModRM; case Code[CodeIdx] of $D8: DoD8; $D9: DoD9; $DA: DoDA; $DB: DoDB; $DC: DoDC; $DD: DoDD; $DE: DoDE; $DF: DoDF; else SetOpcode(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: SetOpcode(OPpi2fw); $0D: SetOpcode(OPpi2fd); $1C: SetOpcode(OPpf2iw); $1D: SetOpcode(OPpf2id); $8A: SetOpcode(OPpfnacc); $8E: SetOpcode(OPpfpnacc); $90: SetOpcode(OPpfcmpge); $94: SetOpcode(OPpfmin); $96: SetOpcode(OPpfrcp); $97: SetOpcode(OPpfrsqrt); $9A: SetOpcode(OPpfsub); $9E: SetOpcode(OPpfadd); $A0: SetOpcode(OPpfcmpgt); $A4: SetOpcode(OPpfmax); $A6: SetOpcode(OPpfrcpit1); $A7: SetOpcode(OPpfrsqit1); $AA: SetOpcode(OPpfsubr); $AE: SetOpcode(OPpfacc); $B0: SetOpcode(OPpfcmpeq); $B4: SetOpcode(OPpfmul); $B6: SetOpcode(OPpfrcpit2); $B7: SetOpcode(OPpmulhrw); $BB: SetOpcode(OPpswapd); $BF: SetOpcode(OPpavgusb); else SetOpcode(OPX_3dnow); end; end; procedure TX86Disassembler.DoGroup1; const OPC: array[0..7] of TOpCode = (OPadd, OPor, OPadc, OPsbb, OPand, OPsub, OPxor, OPcmp); begin DecodeModRM; // group 1a if Code[CodeIdx] = $8F then begin if ModRM.Index = 0 then begin SetOpcode(OPpop); AddEv; end else SetOpcode(OPX_group1a); Exit; end; // Group 1 SetOpcode(OPC[ModRM.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 SetOpcode(OPX_NotGroup1); Exit; end; if (ModRM.Index <> 7) then CheckLock; end; procedure TX86Disassembler.DoGroup2; const OPC: array[0..7] of TOpCode = (OProl, OPror, OPrcl, OPrcr, OPshl, OPshr, OPsal, OPsar); begin DecodeModRM; SetOpcode(OPC[ModRM.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 SetOpcode(OPX_NotGroup2); end; end; procedure TX86Disassembler.DoGroup3; const OPC: array[0..7] of TOpCode = (OPtest, OPtest, OPnot, OPneg, OPmul, OPimul, OPdiv, OPidiv); begin DecodeModRM; SetOpcode(OPC[ModRM.Index]); case Code[CodeIdx] of $F6: begin if ModRM.Index in [0, 1] then begin AddEb; AddIb; end else begin AddEb; end; end; $F7: begin if ModRM.Index in [0, 1] then begin AddEv; AddIz; end else begin AddEv; end; end; else SetOpcode(OPX_NotGroup3); Exit; end; if ModRM.Index in [2, 3] then CheckLock; end; procedure TX86Disassembler.DoGroup4; begin DecodeModRM; if Code[CodeIdx] <> $FE then begin SetOpcode(OPX_NotGroup4); Exit; end; case ModRM.Index of 0: SetOpcode(OPinc); 1: SetOpcode(OPdec); else SetOpcode(OPX_Group4); Exit; end; AddEb; CheckLock; end; procedure TX86Disassembler.DoGroup5; begin DecodeModRM; if Code[CodeIdx] <> $FF then begin SetOpcode(OPX_NotGroup5); Exit; end; case ModRM.Index of 0: begin SetOpcode(OPinc); AddEv; CheckLock; end; 1: begin SetOpcode(OPdec); AddEv; CheckLock; end; 2: begin Force64; SetOpcode(OPcall); AddEv; end; 3: begin SetOpcode(OPcall); AddMp; end; 4: begin Force64; SetOpcode(OPjmp); AddEv; end; 5: begin SetOpcode(OPjmp); AddMp; end; 6: begin Default64; SetOpcode(OPpush); AddEv; end; else SetOpcode(OPX_Group5); end; end; procedure TX86Disassembler.DoGroup6; begin DecodeModRM; if Code[CodeIdx] <> $00 then begin SetOpcode(OPX_NotGroup6); Exit; end; case ModRM.Index of 0: begin SetOpcode(OPsldt); AddMw_Rv; end; 1: begin SetOpcode(OPstr); AddMw_Rv; end; 2: begin SetOpcode(OPlldt); AddEw; end; 3: begin SetOpcode(OPltr); AddEw; end; 4: begin SetOpcode(OPverr); AddEw; end; 5: begin SetOpcode(OPverw); AddEw; end; else SetOpcode(OPX_Group6); end; end; procedure TX86Disassembler.DoGroup7; { Intel and AMD have their own (nonoverlapping) instructions in this group. Decoding is based on: Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2: Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group Number AMD64 Architecture Programmer’s Manual Volume 3: Table A-7. ModRM.reg Extensions for the Secondary Opcode Map and Table A-8. Opcode 01h ModRM Extensions } const RM0: array [0..7] of TOpCode = (OPX_Group7, OPvmcall, OPvmlaunch, OPvmresume, OPvmxoff, OPX_Group7, OPX_Group7, OPX_Group7); RM1: array [0..7] of TOpCode = (OPmonitor, OPmwait, OPclac, OPstac, OPX_Group7, OPX_Group7, OPX_Group7, OPencls); RM2: array [0..7] of TOpCode = (OPgetbv, OPsetbv, OPX_Group7, OPX_Group7, OPvmfunc, OPxend, OPxtest, OPenclu); RM3: array [0..7] of TOpCode = (OPvmrun, OPvmmcall, OPvmload, OPvmsave, OPstgi, OPclgi, OPskinit, OPinvlpga); begin DecodeModRM; if Code[CodeIdx] <> $01 then begin SetOpcode(OPX_NotGroup7); Exit; end; SetOpcode(OPX_Group7); if ModRM.Mode = 3 then begin case ModRM.Index of 0: begin SetOpcode(RM0[ModRM.RM]); end; 1: begin SetOpcode(RM1[ModRM.RM]); end; 2: begin SetOpcode(RM2[ModRM.RM]); end; 3: begin SetOpcode(RM3[ModRM.RM]); end; 4: begin SetOpcode(OPsmsw); AddMw_Rv; end; 5: begin if preF3 in Flags then begin Exclude(Flags, preF3); case ModRM.RM of 0: SetOpcode(OPsetssbsy); 2: SetOpcode(OPsaveprevssp); end; end else if not (preF2 in Flags) then begin case ModRM.RM of 6: SetOpcode(OPrdpkru); 7: SetOpcode(OPwrpkru); end; end; end; 6: begin SetOpcode(OPlmsw); AddEw; end; 7: begin case ModRM.RM of 0: begin Check64; SetOpcode(OPswapgs); end; 1: begin SetOpcode(OPrdtsc, OPSx_p); end; 2: begin if preF3 in Flags then begin Exclude(Flags, preF3); SetOpcode(OPmonitor, OPSx_x); end else if not (preF2 in Flags) then begin SetOpcode(OPmcommit); end; end; 3: begin if [preF2, preF3] * Flags = [] then begin SetOpcode(OPmwait, OPSx_x); end; end; 5: begin if [preF2, preF3] * Flags = [] then begin SetOpcode(OPrdpru); end; end; 6: begin if [preF2, preF3] * Flags = [preF3] then begin Exclude(Flags, preF3); SetOpcode(OPrmpadjust); end else if [preF2, preF3] * Flags = [preF2] then begin Exclude(Flags, preF2); SetOpcode(OPrmpupdate); end; end; 7: begin if [preF2, preF3] * Flags = [preF3] then begin Exclude(Flags, preF3); SetOpcode(OPpsmash); end else if [preF2, preF3] * Flags = [preF2] then begin Exclude(Flags, preF2); SetOpcode(OPpvalidate); end; end; end; end; end; end else begin case ModRM.Index of 0: begin SetOpcode(OPsgdt); AddMs; end; 1: begin SetOpcode(OPsidt); AddMs; end; 2: begin SetOpcode(OPlgdt); AddMs; end; 3: begin SetOpcode(OPlidt); AddMs; end; 4: begin SetOpcode(OPsmsw); AddMw_Rv; end; //5 : invalid 6: begin SetOpcode(OPlmsw); AddEw; end; 7: begin SetOpcode(OPinvlpg); AddMb; end; end; end; end; procedure TX86Disassembler.DoGroup8; const RM8: array [0..7] of TOpCode = (OPX_Group8, OPX_Group8, OPX_Group8, OPX_Group8, OPbt, OPbts, OPbtr, OPbtc); begin DecodeModRM; if Code[CodeIdx] <> $BA then begin SetOpcode(OPX_NotGroup8); Exit; end; if ModRM.Index < 4 then begin SetOpcode(OPX_Group8); Exit; end; AddEv; AddIb; SetOpcode(RM8[ModRM.Index]); if ModRM.Index in [5..7] then CheckLock; end; procedure TX86Disassembler.DoGroup9; var Index: Byte; begin DecodeModRM; if Code[CodeIdx] <> $C7 then begin SetOpcode(OPX_NotGroup9); Exit; end; if ModRM.Index = 1 then begin if OperandSize = os64 then begin SetOpcode(OPcmpxchg, OPSx_16b); AddMdq; end else begin SetOpcode(OPcmpxchg, OPSx_8b); AddMq; end; CheckLock; end else begin SetOpcode(OPX_Group9); end; end; procedure TX86Disassembler.DoGroup10; begin DecodeModRM; if Code[CodeIdx] <> $B9 then begin SetOpcode(OPX_NotGroup10); Exit; end; SetOpcode(OPud1); AddGv;AddEv; end; procedure TX86Disassembler.DoGroup11; begin DecodeModRM; if ModRM.Index <> 0 then begin SetOpcode(OPX_NotGroup11); Exit; end; case Code[CodeIdx] of $C6: begin AddEb; AddIb; end; $C7: begin AddEv; AddIz; end; else SetOpcode(OPX_Group11); Exit; end; SetOpcode(OPmov); end; procedure TX86Disassembler.DoGroup12; const OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrl, OPX_Invalid, OPpsra, OPX_Invalid, OPpsll, OPX_Invalid); begin DecodeModRM; if Code[CodeIdx] <> $71 then begin SetOpcode(OPX_NotGroup12); Exit; end; DecodeSIMD(True, [soNone, so66]); if (SimdOpcode in [soNone, so66]) and (OPC[ModRM.Index] <> OPX_Invalid) then begin SetOpcode(OPC[ModRM.Index], OPSx_w); case SimdOpcode of soNone: begin AddNq; AddIb; end; so66: begin AddUdq; AddIb; end; end; end else begin SetOpcode(OPX_Group12); end; end; procedure TX86Disassembler.DoGroup13; const OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrl, OPX_Invalid, OPpsra, OPX_Invalid, OPpsll, OPX_Invalid); begin DecodeModRM; if Code[CodeIdx] <> $72 then begin SetOpcode(OPX_NotGroup13); Exit; end; DecodeSIMD; if (SimdOpcode in [soNone, so66]) and (OPC[ModRM.Index] <> OPX_Invalid) then begin ClearSIMDPrefix; SetOpcode(OPC[ModRM.Index], OPSx_d); case SimdOpcode of soNone: begin AddNq; AddIb; end; so66: begin AddUdq; AddIb; end; end; end else begin SetOpcode(OPX_Group12); end; end; procedure TX86Disassembler.DoGroup14; const OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrl, OPpsrl, OPX_Invalid, OPX_Invalid, OPpsll, OPpsrl); OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSx_q, OPSx_dq, OPSnone, OPSnone, OPSx_q, OPSx_dq); begin DecodeModRM; if Code[CodeIdx] <> $73 then begin SetOpcode(OPX_NotGroup14); Exit; end; DecodeSIMD; if (SimdOpcode in [soNone, so66]) and (OPC[ModRM.Index] <> OPX_Invalid) then begin ClearSIMDPrefix; SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); case SimdOpcode of soNone: begin if (ModRM.Index = 3) or (ModRM.Index = 7) then SetOpcode(OPX_Group14) else begin AddNq; AddIb; end; end; so66: begin AddUdq; AddIb; end; end; end else begin SetOpcode(OPX_Group14); end; end; procedure TX86Disassembler.DoGroup15; begin DecodeModRM; if Code[CodeIdx] <> $AE then begin SetOpcode(OPX_NotGroup15); Exit; end; if (Flags * [pre66, preF3, preF2] <> []) or (ModRM.Index = 4) then begin SetOpcode(OPX_Group15); Exit; end; case ModRM.Index of 0: begin SetOpcode(OPfxsave); AddM; end; 1: begin SetOpcode(OPfxrstor); AddM; end; 2: begin SetOpcode(OPldmxcsr); AddMd; end; 3: begin SetOpcode(OPstmxcsr); AddMd; end; 5: begin SetOpcode(OPlfence); end; 6: begin SetOpcode(OPmfence); end; 7: begin if ModRM.Mode = 3 then begin SetOpcode(OPlfence) end else begin SetOpcode(OPclflush); AddMb; end; end; end; end; procedure TX86Disassembler.DoGroup16; const OPS: array[0..3] of TOpCodeSuffix = (OPSp_nta, OPSp_t0, OPSp_t1, OPSp_t2); begin DecodeModRM; if Code[CodeIdx] <> $18 then begin SetOpcode(OPX_NotGroup16); Exit; end; if (ModRM.Mode <> 3) and (ModRM.Index < 4) then begin SetOpcode(OPprefetch, OPS[ModRM.Index]); AddMb; end; end; procedure TX86Disassembler.DoGroupP; begin DecodeModRM; if Code[CodeIdx] <> $0D then begin SetOpcode(OPX_NotGroupP); Exit; end; if (ModRM.Mode <> 3) and (ModRM.Index < 2) then begin if ModRM.Index = 0 then SetOpcode(OPprefetch) else SetOpcode(OPprefetch, OPSp_w); AddMb; end; end; procedure TX86Disassembler.Do2ByteOpcode; const INVALID = '**2byte**'; const OPC_5x: array[0..$F] of TOpcode = ( OPX_Invalid, OPsqrt, OPrsqrt, OPrcp, OPand, OPandn, OPor, OPxor, OPadd, OPmul, OPX_Invalid, OPX_Invalid, OPsub, OPmin, OPdiv, OPmax ); OPC_6x: array[0..$F] of TOpCode = ( OPpunpcklbw, OPpunpcklwd, OPpunpckldq, OPpacksswb, OPpcmpgt, OPpcmpgt, OPpcmpgt, OPpackuswb, OPpunpckhbw, OPpunpckhwd, OPpunpckhdq, OPpackssdw, OPpunpcklqdq, OPpunpckhqdq, OPX_Invalid, OPX_Invalid ); OPS_6x: array[0..$F] of TOpCodeSuffix = ( OPSnone, OPSnone, OPSnone, OPSnone, OPSx_b, OPSx_w, OPSx_d, OPSnone, OPSnone, OPSnone, OPSnone, OPSnone, OPSnone, OPSnone, OPSnone, OPSnone ); OPC_Dx: array[0..$F] of TOpCode = ( OPX_Invalid, OPpsrl, OPpsrl, OPpsrl, OPpadd, OPpmull, OPX_Invalid, OPX_Invalid, OPpsubus, OPpsubus, OPpminu, OPpand, OPpaddus, OPpaddus, OPpmaxu, OPpandn ); OPS_Dx: array[0..$F] of TOpCodeSuffix = ( OPSnone, OPSx_w, OPSx_d, OPSx_q, OPSx_q, OPSx_w, OPSnone, OPSnone, OPSx_b, OPSx_w, OPSx_b, OPSnone, OPSx_b, OPSx_w, OPSx_b, OPSnone ); OPC_Ex: array[0..$F] of TOpCode = ( OPpavg, OPpsra, OPpsra, OPpavg, OPpmulhuw, OPpmulhw, OPX_Invalid, OPX_Invalid, OPpsubs, OPpsubs, OPpmins, OPpor, OPpadds, OPpadds, OPpmaxs, OPpxor ); OPS_Ex: array[0..$F] of TOpCodeSuffix = ( OPSx_b, OPSx_w, OPSx_d, OPSx_w, OPSnone, OPSnone, OPSnone, OPSnone, OPSx_b, OPSx_w, OPSx_w, OPSnone, OPSx_b, OPSx_w, OPSx_w, OPSnone ); OPC_Fx: array[0..$F] of TOpCode = ( OPX_Invalid, OPpsll, OPpsll, OPpsll, OPpmuludq, OPpmaddwd, OPpsadbw, OPX_Invalid, OPpsub, OPpsub, OPpsub, OPpsub, OPpadd, OPpadd, OPpadd, OPX_Invalid ); OPS_Fx: array[0..$F] of TOpCodeSuffix = ( OPSnone, OPSx_w, OPSx_d, OPSx_q, OPSnone, OPSnone, OPSnone, OPSnone, OPSx_b, OPSx_w, OPSx_d, OPSx_q, OPSx_b, OPSx_w, OPSx_d, OPSnone ); var idx: Integer; ValidSimd: TSimdOpcodes; begin Inc(CodeIdx); Inc(ModRMIdx); case Code[CodeIdx] of $00: begin DoGroup6; end; $01: begin DoGroup7; end; $02: begin SetOpcode(OPlar); AddGv; AddEw; end; $03: begin SetOpcode(OPlsl); AddGv; AddEw; end; // $04: invalid $05: begin SetOpcode(OPsyscall); end; $06: begin SetOpcode(OPclts); end; $07: begin SetOpcode(OPsysret); end; $08: begin SetOpcode(OPinvd); end; $09: begin SetOpcode(OPwbinvd); end; // $0A: invalid $0B: begin SetOpcode(OPud2); end; // $0C: invalid $0D: begin DoGroupP; end; $0E: begin // AMD SetOpcode(OPfemms); end; $0F: begin // AMD Do3DNow; end; //--- $10: begin DecodeSIMD(True); case SimdOpcode of soNone: begin SetOpcode(OPmovu, OPSx_ps); AddVps; AddWps; end; so66: begin SetOpcode(OPmovu, OPSx_pd); AddVpd; AddWpd; end; soF2: begin SetOpcode(OPmov, OPSx_sd); AddVsd; AddWsd; end; soF3: begin SetOpcode(OPmov, OPSx_ss); AddVss; AddWss; end; end; end; $11: begin DecodeSIMD(True); case SimdOpcode of soNone: begin SetOpcode(OPmovu, OPSx_ps); AddWps; AddVps; end; so66: begin SetOpcode(OPmovu, OPSx_pd); AddWpd; AddVpd; end; soF2: begin SetOpcode(OPmov, OPSx_sd); AddWsd; AddVsd; end; soF3: begin SetOpcode(OPmov, OPSx_ss); AddWss; AddVss; end; end; end; $12: begin DecodeSIMD(True); case SimdOpcode of soNone: begin DecodeModRM; if ModRM.Mode = 3 then begin SetOpcode(OPmovhlps); AddVps; AddUq end else begin SetOpcode(OPmovl, OPSx_ps); AddVps; AddMq end; end; so66: begin SetOpcode(OPmovl, OPSx_pd); AddVsd; AddMq; end; soF2: begin SetOpcode(OPmovddup); AddVpd; AddWsd; end; soF3: begin SetOpcode(OPmovsldup); AddVps; AddWps; end; end; end; $13: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmovl, OPSx_ps); AddMq; AddVps; end; so66: begin SetOpcode(OPmovl, OPSx_pd); AddMq; AddVsd; end; end; end; $14: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPunpckl, OPSx_ps); AddVps; AddWq; end; so66: begin SetOpcode(OPunpckl, OPSx_pd); AddVpd; AddWq; end; end; end; $15: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPunpckh, OPSx_ps); AddVps; AddWq; end; so66: begin SetOpcode(OPunpckh, OPSx_pd); AddVpd; AddWq; end; end; end; $16: begin DecodeSIMD(True, [soNone, so66, soF3]); case SimdOpcode of soNone: begin DecodeModRM; if ModRM.Mode = 3 then begin SetOpcode(OPmovlh, OPSx_ps); AddVps; AddUq end else begin SetOpcode(OPmovh, OPSx_ps); AddVps; AddMq end; end; so66: begin SetOpcode(OPmovh, OPSx_pd); AddVsd; AddMq; end; soF3: begin SetOpcode(OPmovshdup); AddVps; AddWps; end; end; end; $17: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmovh, OPSx_ps); AddMq; AddVps; end; so66: begin SetOpcode(OPmovh, OPSx_pd); AddMq; AddVsd; end; end; end; $18: begin DoGroup16; end; $19..$1D: begin SetOpcode(OPnop); AddEv; end; $1E: begin DecodeSIMD(True, [soNone, soF3]); case SimdOpcode of soNone: begin SetOpcode(OPNop); AddEv; end; soF3: begin SetOpcode(OPrdss, OPSx_p); AddRy; end; end; end; $1F: begin SetOpcode(OPnop); AddEv; end; //--- $20: begin SetOpcode(OPmov); AddRd_q; AddCd_q; end; $21: begin SetOpcode(OPmov); AddRd_q; AddDd_q; end; $22: begin SetOpcode(OPmov); AddCd_q; AddRd_q; end; $23: begin SetOpcode(OPmov); AddDd_q; AddRd_q; end; // $24..$27: OPX_Invalid $28: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmova, OPSx_ps); AddVps; AddWps; end; so66: begin SetOpcode(OPmova, OPSx_pd); AddVpd; AddWpd; end; end; end; $29: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmova, OPSx_ps); AddWps; AddVps; end; so66: begin SetOpcode(OPmova, OPSx_pd); AddWpd; AddVpd; end; end; end; $2A: begin DecodeSIMD(True); case SimdOpcode of soNone: begin SetOpcode(OPcvtpi2, OPSx_ps); AddVps; AddQq; end; so66: begin SetOpcode(OPcvtpi2, OPSx_pd); AddVpd; AddQq; end; soF2: begin SetOpcode(OPcvtsi2, OPSx_sd); AddVsd; AddEy; end; soF3: begin SetOpcode(OPcvtsi2, OPSx_ss); AddVss; AddEy; end; end; end; $2B: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmovnt, OPSx_ps); AddMdq; AddVps; end; so66: begin SetOpcode(OPmovnt, OPSx_pd); AddMdq; AddVpd; end; end; end; $2C: begin DecodeSIMD(True); case SimdOpcode of soNone: begin SetOpcode(OPcvttps2, OPSx_pi); AddPq; AddWps; end; so66: begin SetOpcode(OPcvttpd2, OPSx_pi); AddPq; AddWpd; end; soF2: begin SetOpcode(OPcvttsd2, OPSx_si); AddGy; AddWsd; end; soF3: begin SetOpcode(OPcvttss2, OPSx_si); AddGy; AddWss; end; end; end; $2D: begin DecodeSIMD(True); case SimdOpcode of soNone: begin SetOpcode(OPcvtps2, OPSx_pi); AddPq; AddWps; end; so66: begin SetOpcode(OPcvtpd2, OPSx_pi); AddPq; AddWpd; end; soF2: begin SetOpcode(OPcvtsd2, OPSx_si); AddGy; AddWsd; end; soF3: begin SetOpcode(OPcvtss2, OPSx_si); AddGy; AddWss; end; end; end; $2E: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPucomi, OPSx_ss); AddVss; AddWss; end; so66: begin SetOpcode(OPucomi, OPSx_sd); AddVsd; AddWsd; end; end; end; $2F: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPcomi, OPSx_ss); AddVss; AddWss; end; so66: begin SetOpcode(OPcomi, OPSx_sd); AddVsd; AddWsd; end; end; end; //--- $30: begin SetOpcode(OPwrmsr); end; $31: begin SetOpcode(OPrdtsc); end; $32: begin SetOpcode(OPrdmsr); end; $33: begin SetOpcode(OPrdpmc); end; $34: begin SetOpcode(OPsysenter); end; $35: begin SetOpcode(OPsysexit); end; // $36..$3F: OPX_Invalid //--- $40..$4F: begin SetOpcode(OPcmov__, StdCond(Code[CodeIdx])); AddGv; AddEv; end; //--- $50: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmovmsk, OPSx_ps); AddGd; AddUps; end; so66: begin SetOpcode(OPmovmsk, OPSx_pd); AddGd; AddUpd; end; end; end; $51..$59, $5C..$5F: begin case Code[CodeIdx] of $52: ValidSimd := [soNone, soF3]; $53: ValidSimd := [soNone, soF3]; $54: ValidSimd := [soNone, so66]; $55: ValidSimd := [soNone, so66]; $56: ValidSimd := [soNone, so66]; $57: ValidSimd := [soNone, so66]; else ValidSimd := [soNone, so66, soF2, soF3]; end; DecodeSIMD(True, ValidSimd); if SimdOpcode in ValidSimd then begin case SimdOpcode of soNone: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_ps); AddVps; AddWps; end; so66: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_pd); AddVpd; AddWpd; end; soF2: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_sd); AddVsd; AddWsd; end; soF3: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_ss); AddVss; AddWss; end; end; end; end; $5A: begin DecodeSIMD(True); case SimdOpcode of soNone: begin SetOpcode(OPcvtps2, OPSx_pd); AddVpd; AddWps; end; so66: begin SetOpcode(OPcvtpd2, OPSx_ps); AddVps; AddWpd; end; soF2: begin SetOpcode(OPcvtsd2, OPSx_ss); AddVss; AddWsd; end; soF3: begin SetOpcode(OPcvtss2, OPSx_sd); AddVsd; AddWss; end; end; end; $5B: begin DecodeSIMD(True, [soNone, so66, soF3]); case SimdOpcode of soNone: begin SetOpcode(OPcvtdq2, OPSx_ps); AddVps; AddWdq; end; so66: begin SetOpcode(OPcvtps2, OPSx_dq); AddVdq; AddWps; end; soF3: begin SetOpcode(OPcvttps2, OPSx_dq); AddVdq; AddWps; end; end; end; // $5C..$5F: see $51 //--- $60..$6B: begin idx := Code[CodeIdx] and $F; DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPC_6x[idx], OPS_6x[idx]); AddPq; AddQd; end; so66: begin SetOpcode(OPC_6x[idx], OPS_6x[idx]); AddVdq; if Code[CodeIdx] = $6B then AddWdq else AddWq; end; end; end; $6C..$6D: begin idx := Code[CodeIdx] and $F; DecodeSIMD(True, [so66]); if SimdOpcode = so66 then begin SetOpcode(OPC_6x[idx], OPS_6x[idx]); AddVdq; if Code[CodeIdx] = $6B then AddWdq else AddWq; end; end; $6E: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmov, OPSx_d); AddPq; AddEy; end; so66: begin SetOpcode(OPmov, OPSx_d); AddVdq; AddEy; end; end; end; $6F: begin DecodeSIMD(True, [soNone, so66, soF3]); case SimdOpcode of soNone: begin SetOpcode(OPmov, OPSx_q); AddPq; AddQq; end; so66: begin SetOpcode(OPmov, OPSx_dqa); AddVdq; AddWdq; end; soF3: begin SetOpcode(OPmov, OPSx_dqu); AddVdq; AddWdq; end; end; end; //--- $70: begin DecodeSIMD(True); case SimdOpcode of soNone: begin SetOpcode(OPpshuf, OPSx_w); AddPq; AddQq; AddIb; end; so66: begin SetOpcode(OPpshuf, OPSx_d); AddVdq; AddWdq; AddIb; end; soF2: begin SetOpcode(OPpshuf, OPSx_lw); AddVq; AddWq; AddIb; end; soF3: begin SetOpcode(OPpshuf, OPSx_hw); AddVq; AddWq; AddIb; end; end; end; $71: begin DoGroup12 end; $72: begin DoGroup13 end; $73: begin DoGroup14 end; $74: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPpcmpeq, OPSx_b); AddPq; AddQq; end; so66: begin SetOpcode(OPpcmpeq, OPSx_b); AddVdq; AddWdq; end; end; end; $75: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPpcmpeq, OPSx_w); AddPq; AddQq; end; so66: begin SetOpcode(OPpcmpeq, OPSx_w); AddVdq; AddWdq; end; end; end; $76: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPpcmpeq, OPSx_d); AddPq; AddQq; end; so66: begin SetOpcode(OPpcmpeq, OPSx_d); AddVdq; AddWdq; end; end; end; $77: begin DecodeSIMD(True, [soNone]); if SimdOpcode = soNone then SetOpcode(OPemms); end; $78: begin DecodeSIMD(True, [soNone]); if SimdOpcode = soNone then begin SetOpcode(OPvmread); AddEy; AddGy; end; end; $79: begin DecodeSIMD(True, [soNone]); if SimdOpcode = soNone then begin SetOpcode(OPvmwrite); AddGy; AddEy; end; end; // $7A..$7B: OPX_Invalid $7C: begin DecodeSIMD(True, [so66, soF2]); case SimdOpcode of so66: begin SetOpcode(OPhadd, OPSx_pd); AddVpd; AddWpd; end; soF2: begin SetOpcode(OPhadd, OPSx_ps); AddVps; AddWps; end; end; end; $7D: begin DecodeSIMD(True, [so66, soF2]); case SimdOpcode of so66: begin SetOpcode(OPsub, OPSx_pd); AddVpd; AddWpd; end; soF2: begin SetOpcode(OPsub, OPSx_ps); AddVps; AddWps; end; end; end; $7E: begin DecodeSIMD(True, [soNone, so66, soF3]); case SimdOpcode of soNone: begin SetOpcode(OPmov, OPSx_d); AddEy; AddPy; end; so66: begin SetOpcode(OPmov, OPSx_d); AddEy; AddVy; end; soF3: begin SetOpcode(OPmov, OPSx_q); AddVq; AddWq; end; end; end; $7F: begin DecodeSIMD(True, [soNone, so66, soF3]); case SimdOpcode of soNone: begin SetOpcode(OPmov, OPSx_q); AddQq; AddPq; end; so66: begin SetOpcode(OPmov, OPSx_dqa); AddWdq; AddVdq; end; soF3: begin SetOpcode(OPmov, OPSx_dqu); AddWdq; AddVdq; end; end; end; //--- $80..$8F: begin Force64; SetOpcode(OPj__, StdCond(Code[CodeIdx])); AddJz; end; //--- $90..$9F: begin SetOpcode(OPset__, StdCond(Code[CodeIdx])); AddEb; end; //--- $A0: begin Default64; SetOpcode(OPpush); AddOperand('fs'); end; $A1: begin Default64; SetOpcode(OPpop); AddOperand('fs'); end; $A2: begin SetOpcode(OPcpuid); end; $A3: begin SetOpcode(OPbt); AddEv; AddGv; end; $A4: begin SetOpcode(OPshl, OPSx_d); AddEv; AddGv; AddIb; end; $A5: begin SetOpcode(OPshl, OPSx_d); AddEv; AddGv; AddOperand('cl'); end; // $A6..$A7: OPX_Invalid $A8: begin Default64; SetOpcode(OPpush); AddOperand('gs'); end; $A9: begin Default64; SetOpcode(OPpop); AddOperand('gs'); end; $AA: begin SetOpcode(OPrsm); end; $AB: begin SetOpcode(OPbts); AddEv; AddGv; end; $AC: begin SetOpcode(OPshr, OPSx_d); AddEv; AddGv; AddIb; end; $AD: begin SetOpcode(OPshl, OPSx_d); AddEv; AddGv; AddOperand('cl'); end; $AE: begin DoGroup15; end; $AF: begin SetOpcode(OPimul); AddGv; AddEv; end; //--- $B0: begin SetOpcode(OPcmpxchg); CheckLock; AddEb; AddGb; end; $B1: begin SetOpcode(OPcmpxchg); CheckLock; AddEv; AddGv; end; $B2: begin SetOpcode(OPlss); AddGz; AddMp; end; $B3: begin SetOpcode(OPbtr); AddEv; AddGv; end; $B4: begin SetOpcode(OPlfs); AddGz; AddMp; end; $B5: begin SetOpcode(OPlgs); AddGz; AddMp; end; $B6: begin SetOpcode(OPmovzx); AddGv; AddEb; end; $B7: begin SetOpcode(Opmovzx); AddGv; AddEw; end; // $B8: OPX_Invalid $B9: begin DoGroup10; end; $BA: begin DoGroup8; end; $BB: begin SetOpcode(OPbtc); AddEv; AddGv; end; $BC: begin SetOpcode(OPbsf); AddGv; AddEv; end; $BD: begin SetOpcode(OPbsr); AddGv; AddEv; end; $BE: begin SetOpcode(OPmovsx); AddGv; AddEb; end; $BF: begin SetOpcode(OPmovsx); AddGv; AddEw; end; //--- $C0: begin SetOpcode(OPxadd); CheckLock; AddEb; AddGb; end; $C1: begin SetOpcode(OPxadd); CheckLock; AddEv; AddGv; end; $C2: begin DecodeSIMD(True); case SimdOpcode of soNone: begin SetOpcode(OPcmp, OPSx_ps); AddVps; AddWps; AddIb end; so66: begin SetOpcode(OPcmp, OPSx_pd); AddVpd; AddWpd; AddIb end; soF2: begin SetOpcode(OPcmp, OPSx_sd); AddVsd; AddWsd; AddIb end; soF3: begin SetOpcode(OPcmp, OPSx_ss); AddVss; AddWss; AddIb end; end; end; $C3: begin DecodeSIMD(True, [soNone]); if SimdOpcode = soNone then begin SetOpcode(OPmovnt, OPSx_i); AddMy; AddGy; end; end; $C4: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPpinsr, OPSx_w); AddPq; AddEw; AddIb end; so66: begin SetOpcode(OPpinsr, OPSx_w); AddVdq; AddEw; AddIb end; end; end; $C5: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPpextr, OPSx_w); AddGd; AddNq; AddIb end; so66: begin SetOpcode(OPpextr, OPSx_w); AddGd; AddUdq; AddIb end; end; end; $C6: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPshuf, OPSx_ps); AddVps; AddWps; AddIb end; so66: begin SetOpcode(OPshuf, OPSx_pd); AddVpd; AddWpd; AddIb end; end; end; $C7: begin DoGroup9; end; $C8..$CF: begin SetOpcode(OPbswap); AddReg(regGeneral, OperandSize, Code[CodeIdx] and $07); end; //--- $D0: begin DecodeSIMD(True, [so66, soF2]); case SimdOpcode of so66: begin SetOpcode(OPaddsub, OPSx_pd); AddVpd; AddWpd; end; soF2: begin SetOpcode(OPaddsub, OPSx_ps); AddVps; AddWps; end; end; end; $D1..$D5, $D8..$DF: begin idx := Code[CodeIdx] and $F; DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPC_Dx[idx], OPS_Dx[idx]); AddPq; AddQq; end; so66: begin SetOpcode(OPC_Dx[idx], OPS_Dx[idx]); AddVdq; AddWdq; end; end; end; $D6: begin DecodeSIMD(True, [so66, soF2, soF3]); case SimdOpcode of so66: begin SetOpcode(OPmov, OPSx_q); AddWq; AddVq; end; soF2: begin SetOpcode(OPmovdq2q); AddPq; AddUq; end; soF3: begin SetOpcode(OPmovq2dq); AddVdq; AddNq; end; end; end; $D7: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPpmovmskb); AddGd; AddNq; end; so66: begin SetOpcode(OPpmovmskb); AddGd; AddUdq; end; end; end; // $D8..$DF: see $D1 //--- $E0..$E5, $E8..$EF: begin idx := Code[CodeIdx] and $F; DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPC_Ex[idx], OPS_Ex[idx]); AddPq; AddQq; end; so66: begin SetOpcode(OPC_Ex[idx], OPS_Ex[idx]); AddVdq; AddWdq; end; end; end; $E6: begin DecodeSIMD(True, [so66, soF2, soF3]); case SimdOpcode of so66: begin SetOpcode(OPcvttpd2, OPSx_dq); AddVq; AddWpd; end; soF2: begin SetOpcode(OPcvtpd2, OPSx_dq); AddVq; AddWpd; end; soF3: begin SetOpcode(OPcvtdq2, OPSx_pd); AddVpd; AddWq; end; end; end; $E7: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmovnt, OPSx_q); AddMq; AddPq; end; so66: begin SetOpcode(OPmovnt, OPSx_dqu); AddMdq; AddVdq; end; end; end; // $E8..$EF: see $E0 $F0: begin if preF2 in Flags then begin SetOpcode(OPlddqu); AddVpd; AddMdq; end; end; $F1..$F6, $F8..$FE: begin idx := Code[CodeIdx] and $F; DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPC_Fx[idx], OPS_Fx[idx]); AddPq; AddQq; end; so66: begin SetOpcode(OPC_Fx[idx], OPS_Fx[idx]); AddVdq; AddWdq; end; end; end; $F7: begin DecodeSIMD(True, [soNone, so66]); case SimdOpcode of soNone: begin SetOpcode(OPmaskmov, OPSx_q); AddPq; AddNq; end; so66: begin SetOpcode(OPmaskmov, OPSx_dqu); AddVdq; AddUdq; end; end; end; // $F8..$FE: see $F1 // $FF: OPX_Invalid else SetOpcode(OPX_Invalid); end; end; procedure TX86Disassembler.DoDisassemble; begin SetOpcode(OPX_InternalUnknown); repeat ModRMIdx := CodeIdx + 1; case Code[CodeIdx] of $00..$05: begin SetOpcode(OPadd); CheckLock; AddStdOperands(Code[CodeIdx]); end; $06: begin SetOpcode(OPpush); Check32; AddOperand('es'); end; $07: begin SetOpcode(OPpop); Check32; AddOperand('es'); end; $08..$0D: begin SetOpcode(OPor); CheckLock; AddStdOperands(Code[CodeIdx]); end; $0E: begin SetOpcode(OPpush); Check32; AddOperand('cs'); end; $0F: begin Do2ByteOpcode; end; //--- $10..$15: begin SetOpcode(OPadc); CheckLock; AddStdOperands(Code[CodeIdx]); end; $16: begin SetOpcode(OPpush); Check32; AddOperand('ss'); end; $17: begin SetOpcode(OPpop); Check32; AddOperand('ss'); end; $18..$1D: begin SetOpcode(OPsbb); CheckLock; AddStdOperands(Code[CodeIdx]); end; $1E: begin SetOpcode(OPpush); Check32; AddOperand('ds'); end; $1F: begin SetOpcode(OPpop); Check32; AddOperand('ds'); end; //--- $20..$25: begin SetOpcode(OPand); CheckLock; AddStdOperands(Code[CodeIdx]); end; $26: begin Instruction^.Segment := Instruction^.Segment + Ignore64('es:'); end; $27: begin SetOpcode(OPdaa); Check32; end; $28..$2D: begin SetOpcode(OPsub); CheckLock; AddStdOperands(Code[CodeIdx]); end; $2E: begin Instruction^.Segment := Instruction^.Segment + Ignore64('cs:'); end; $2F: begin SetOpcode(OPdas); Check32; end; //--- $30..$35: begin SetOpcode(OPxor); CheckLock; AddStdOperands(Code[CodeIdx]); end; $36: begin Instruction^.Segment := Instruction^.Segment + Ignore64('ss:'); end; $37: begin SetOpcode(OPaaa); Check32; end; $38..$3D: begin SetOpcode(OPcmp); AddStdOperands(Code[CodeIdx]); end; $3E: begin Instruction^.Segment := Instruction^.Segment + Ignore64('ds:'); end; $3F: begin SetOpcode(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 if Code[CodeIdx] <= $47 then SetOpcode(OPinc) else SetOpcode(OPdec); CheckLock; AddReg(regGeneral, OperandSize, Code[CodeIdx] and $07); end; end; //--- $50..$57: begin Default64; SetOpcode(OPpush); AddReg(regGeneral, OperandSize, Code[CodeIdx] and $07); end; $58..$5F: begin Default64; SetOpcode(OPpop); AddReg(regGeneral, OperandSize, Code[CodeIdx] and $07); end; //--- $60: begin if OperandSize = os16 then SetOpcode(OPpusha) else SetOpcode(OPpusha, OPSx_d); Check32; end; $61: begin if OperandSize = os16 then SetOpcode(OPpopa) else SetOpcode(OPpopa, OPSx_d); Check32; end; $62: begin SetOpcode(OPbound); Check32; AddGv; AddMa; end; $63: begin if ProcessMode = dm64 then begin SetOpcode(OPmovsx, OPSx_d); AddGv; AddEd; end else begin SetOpcode(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; SetOpcode(OPpush); AddIz; end; $69: begin SetOpcode(OPimul); AddGv; AddEv; AddIz; end; $6A: begin Default64; SetOpcode(OPpush); AddIb; end; $6B: begin SetOpcode(OPimul); AddGv; AddEv; AddIb; end; $6C: begin SetOpcode(OPins, OPSx_b); CheckRepeat; {$ifdef verbose_string_instructions} AddYb; AddOperand('dx', os16); {$endif} end; $6D: begin if OperandSize = os16 then SetOpcode(OPins, OPSx_w) else SetOpcode(OPins, OPSx_d); CheckRepeat; {$ifdef verbose_string_instructions} AddYz; AddOperand('dx', os16); {$endif} end; $6E: begin SetOpcode(OPouts, OPSx_b); CheckRepeat; {$ifdef verbose_string_instructions} AddOperand('dx', os16); AddXb; {$endif} end; $6F: begin if OperandSize = os16 then SetOpcode(OPouts, OPSx_w) else SetOpcode(OPouts, OPSx_d); CheckRepeat; {$ifdef verbose_string_instructions} AddOperand('dx', os16); AddXz; {$endif} end; $70..$7F: begin Force64; SetOpcode(OPj__, StdCond(Code[CodeIdx])); AddJb; end; //--- $80..$83: begin DoGroup1; end; $84: begin SetOpcode(OPtest); AddEb; AddGb; end; $85: begin SetOpcode(OPtest); AddEv; AddGv; end; $86: begin SetOpcode(OPxchg); CheckLock; AddEb; AddGb; end; $87: begin SetOpcode(OPxchg); CheckLock; AddEv; AddGv; end; $88..$8B: begin SetOpcode(OPmov); AddStdOperands(Code[CodeIdx]); end; $8C: begin SetOpcode(OPmov); AddMw_Rv; AddSw; end; $8D: begin SetOpcode(OPlea); AddGv; AddM; end; $8E: begin SetOpcode(OPmov); AddSw; AddEw; end; $8F: begin Default64; DoGroup1; end; //--- $90..$97: begin if (Code[CodeIdx] = $90) and not (rexB in Flags) then SetOpcode(OPnop) else begin SetOpcode(OPxchg); AddReg(regGeneral, OperandSize, Code[CodeIdx] and $07); AddReg(regGeneral, OperandSize, 0); end; end; $98: begin case OperandSize of os64: SetOpcode(OPcdqe); os32: SetOpcode(OPcwde); else SetOpcode(OPcbw); end; end; $99: begin case OperandSize of os64: SetOpcode(OPcqo); os32: SetOpcode(OPcdq); else SetOpcode(OPcwd); end; end; $9A: begin SetOpcode(OPcall); Check32; AddAp; end; $9B: begin SetOpcode(OPfwait); end; $9C: begin Default64; case OperandSize of os64: SetOpcode(OPpushf, OPSx_q); os32: SetOpcode(OPpushf, OPSx_d); else SetOpcode(OPpushf); end; AddFv; end; $9D: begin Default64; case OperandSize of os64: SetOpcode(OPpopf, OPSx_q); os32: SetOpcode(OPpopf, OPSx_d); else SetOpcode(OPpopf); end; AddFv; end; $9E: begin SetOpcode(OPsahf); end; $9F: begin SetOpcode(OPlahf); end; //--- $A0: begin SetOpcode(OPmov); AddReg(regGeneral, os8, 0); AddOb; end; $A1: begin SetOpcode(OPmov); AddReg(regGeneral, OperandSize, 0); AddOv; end; $A2: begin SetOpcode(OPmov); AddOb; AddOperand('al', os8); end; $A3: begin SetOpcode(OPmov); AddOv; AddReg(regGeneral, OperandSize, 0); end; $A4: begin SetOpcode(OPmovs, OPSx_b); CheckRepeat; {$ifdef verbose_string_instructions} AddYb; AddXb; {$endif} end; $A5: begin case OperandSize of os64: SetOpcode(OPmovs, OPSx_q); os32: SetOpcode(OPmovs, OPSx_d); else SetOpcode(OPmovs, OPSx_w); end; CheckRepeat; {$ifdef verbose_string_instructions} AddYv; AddXv; {$endif} end; $A6: begin SetOpcode(OPcmps, OPSx_b); CheckRepeatX; {$ifdef verbose_string_instructions} AddXb; AddYb; {$endif} end; $A7: begin case OperandSize of os64: SetOpcode(OPcmps, OPSx_q); os32: SetOpcode(OPcmps, OPSx_d); else SetOpcode(OPcmps, OPSx_w); end; CheckRepeatX; {$ifdef verbose_string_instructions} AddYv; AddXv; {$endif} end; $A8: begin SetOpcode(OPtest); AddOperand('al', os8); AddIb; end; $A9: begin SetOpcode(OPtest); AddReg(regGeneral, OperandSize, 0); AddIv; end; $AA: begin SetOpcode(OPstos, OPSx_b); CheckRepeat; {$ifdef verbose_string_instructions} AddYb; AddReg(regGeneral, os8, 0); {$endif} end; $AB: begin case OperandSize of os64: SetOpcode(OPstos, OPSx_q); os32: SetOpcode(OPstos, OPSx_d); else SetOpcode(OPstos, OPSx_w); end; CheckRepeat;; {$ifdef verbose_string_instructions} AddYv; AddReg(regGeneral, OperandSize, 0); {$endif} end; $AC: begin SetOpcode(OPlods, OPSx_b); CheckRepeat; {$ifdef verbose_string_instructions} AddReg(regGeneral, os8, 0) AddXb; {$endif} end; $AD: begin case OperandSize of os64: SetOpcode(OPlods, OPSx_q); os32: SetOpcode(OPlods, OPSx_d); else SetOpcode(OPlods, OPSx_w); end; CheckRepeat; {$ifdef verbose_string_instructions} AddReg(regGeneral, OperandSize, 0); AddXv; {$endif} end; $AE: begin SetOpcode(OPscas, OPSx_b); CheckRepeatX; {$ifdef verbose_string_instructions} AddReg(regGeneral, os8, 0); AddYb; {$endif} end; $AF: begin case OperandSize of os64: SetOpcode(OPscas, OPSx_q); os32: SetOpcode(OPscas, OPSx_d); else SetOpcode(OPscas, OPSx_w); end; CheckRepeatX; {$ifdef verbose_string_instructions} AddReg(regGeneral, OperandSize, 0); AddYv; {$endif} end; //--- $B0..$B7: begin SetOpcode(OPmov); AddReg(regGeneral, os8, Code[CodeIdx] and $07); AddIb; end; $B8..$BF: begin SetOpcode(OPmov); AddReg(regGeneral, OperandSize, Code[CodeIdx] and $07); AddIv; end; //--- $C0..$C1: begin DoGroup2; end; $C2: begin Force64; SetOpcode(OPret); AddIw; end; $C3: begin Force64; SetOpcode(OPret); end; $C4: begin SetOpcode(OPles); AddGz; AddMp; end; $C5: begin SetOpcode(OPlds); AddGz; AddMp; end; $C6..$C7: begin DoGroup11; end; $C8: begin SetOpcode(OPenter); AddIw; AddIb; end; $C9: begin Default64; SetOpcode(OPleave); end; $CA: begin SetOpcode(OPretf); AddIw; end; $CB: begin SetOpcode(OPretf); end; $CC: begin SetOpcode(OPint3); end; $CD: begin SetOpcode(OPint); AddIb; end; $CE: begin SetOpcode(OPinto); Check32; end; $CF: begin case OperandSize of os64: SetOpcode(OPiret, OPSx_q); os32: SetOpcode(OPiret, OPSx_d); else SetOpcode(OPiret); end; end; //--- $D0..$D3: begin DoGroup2; end; $D4: begin SetOpcode(OPaam); Check32; end; $D5: begin SetOpcode(OPaad); Check32; end; $D6: begin // AMD (old) SetOpcode(OPsalc); Check32; end; $D7: begin SetOpcode(OPxlat); end; $D8..$DF: begin DoX87; end; //--- $E0: begin Force64; SetOpcode(OPloop, OPSc_ne); AddJb; end; $E1: begin Force64; SetOpcode(OPloop, OPSc_e); AddJb; end; $E2: begin Force64; SetOpcode(OPloop); AddJb; end; $E3: begin case AddressSize of as16: begin Check32; SetOpcode(OPjcxz); end; as32: begin SetOpcode(OPjecxz); end; as64: begin Check64; SetOpcode(OPjrcxz); end; end; AddJb; end; $E4: begin SetOpcode(OPin); AddReg(regGeneral, os8, 0); AddIb; end; $E5: begin SetOpcode(OPin); AddReg(regGeneral, OperandSize, 0); AddIb; end; $E6: begin SetOpcode(OPout); AddIb; AddReg(regGeneral, os8, 0); end; $E7: begin SetOpcode(OPout); AddIb; AddReg(regGeneral, OperandSize, 0); end; $E8: begin Force64; SetOpcode(OPcall); AddJz; end; $E9: begin Force64; SetOpcode(OPjmp); AddJz; end; $EA: begin SetOpcode(OPjmp); Check32; AddAp; end; $EB: begin Force64; SetOpcode(OPjmp); AddJb; end; $EC: begin SetOpcode(OPin); AddReg(regGeneral, os8, 0); AddReg(regGeneral, os16, 2); end; $ED: begin SetOpcode(OPin); AddReg(regGeneral, OperandSize, 0); AddReg(regGeneral, os16, 2); end; $EE: begin SetOpcode(OPout); AddReg(regGeneral, os16, 2); AddReg(regGeneral, os8, 0); end; $EF: begin SetOpcode(OPout); AddReg(regGeneral, os16, 2); AddReg(regGeneral, OperandSize, 0); end; $F0: begin Include(Flags, preLock); end; $F1: begin SetOpcode(OPint1); end; $F2: begin Include(Flags, preF2); end; $F3: begin Include(Flags, preF3); end; $F4: begin SetOpcode(OPhlt); end; $F5: begin SetOpcode(OPcmc); end; $F6..$F7: begin DoGroup3; end; $F8: begin SetOpcode(OPclc); end; $F9: begin SetOpcode(OPstc); end; $FA: begin SetOpcode(OPcli); end; $FB: begin SetOpcode(OPsti); end; $FC: begin SetOpcode(OPcld); end; $FD: begin SetOpcode(OPstd); end; $FE: begin DoGroup4; end; $FF: begin DoGroup5; end; else SetOpcode(OPX_Invalid); 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.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; SetOpcode(OPX_Invalid); 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.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.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.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.Opcode; end; procedure TX86AsmDecoder.Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); const MEMPTR: array[TOperandSize] of string = ( { os0 } '', { os8 } 'byte ptr ', { os16 } 'word ptr ', { os32 } 'dword ptr ', { os64 } 'qword ptr ', { os48 } '', { os80 } 'tbyte ptr ', { os128 } '16byte ptr ', { os256 } '32byte ptr ', { os512 } '64byte 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 S = '' then Continue; // 3DNow adds a dummy operand to adjust the size 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.Opcode]; OpcodeName := OpcodeName + OPCODE_SUFFIX_NAME[Instr.OpCode.Suffix]; 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.