lazarus/components/fpdebug/fpdbgdisasx86.pp

4267 lines
116 KiB
ObjectPascal
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ $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 <marc@@dommelstein.nl>)
***************************************************************************
* *
* 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 <http://www.gnu.org/copyleft/gpl.html>. 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 Developers 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 Programmers Manual Volume 3:
Table A-13. Immediate Byte for 3DNow!(tm) Opcodes, Low Nibble 07h
and
Table A-14. Immediate Byte for 3DNow!(tm) Opcodes, Low Nibble 8Fh
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 Developers 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 Developers Manual Volume 2:
// A.2 KEY TO ABBREVIATIONS
//
// and
//
// AMD64 Architecture Programmers 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 Developers 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 Developers Manual Volume 2:
Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group Number
AMD64 Architecture Programmers 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.