mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-01 06:03:45 +02:00
6136 lines
187 KiB
ObjectPascal
6136 lines
187 KiB
ObjectPascal
{ $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+}
|
||
{$IFDEF INLINE_OFF}{$INLINE OFF}{$ENDIF}
|
||
interface
|
||
|
||
{.$define debug_OperandSize}
|
||
{.$define verbose_string_instructions}
|
||
|
||
uses
|
||
SysUtils, FpDbgUtil, FpDbgInfo, DbgIntfBaseTypes, FpdMemoryTools,
|
||
FpDbgClasses, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazClasses;
|
||
|
||
{
|
||
The function Disassemble decodes the instruction at the given address.
|
||
After decoding, the address increased to the next instruction.
|
||
The following chars are used to indicate problems with instruction
|
||
sequenses:
|
||
** invalid opcode
|
||
-- reserved opcode
|
||
() ignored opcode
|
||
?? unspecified
|
||
!! internal error, a group got called for an opcode which wasn't decoded there
|
||
|
||
The disassembler starts to decode the first byte according to
|
||
|
||
Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2:
|
||
Table A-2. One-byte Opcode Map: (00H — F7H)
|
||
and
|
||
Table A-2. One-byte Opcode Map: (08H — FFH)
|
||
|
||
The 3DNow!(tm) instructions are decoded according to
|
||
AMD64 Architecture Programmer’s Manual Volume 3:
|
||
Table A-13. Immediate Byte for 3DNow!(tm) Opcodes, Low Nibble 0–7h
|
||
and
|
||
Table A-14. Immediate Byte for 3DNow!(tm) Opcodes, Low Nibble 8–Fh
|
||
|
||
The routines Addxx use the same abbriviations as used in those tables
|
||
|
||
}
|
||
|
||
|
||
type
|
||
// rexB, rexX, rexR, rexW see
|
||
// Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2:
|
||
// Table 2-4. REX Prefix Fields [BITS: 0100WRXB]
|
||
|
||
TFlag = (
|
||
flagRex, // $4x: set for any $4X
|
||
flagSib,
|
||
flagModRM,
|
||
rexB, // $4x bit 0: Extension of the ModR/M r/m field, SIB base field, or Opcode reg field
|
||
rexX, // $4x bit 1: Extension of the SIB index field
|
||
rexR, // $4x bit 2: Extension of the ModR/M reg field
|
||
rexW, // $4x bit 3: 64 Bit Operand Size
|
||
pre66, // $66: Operand-size override prefix (32 and 64 bit) or SIMD prefix
|
||
preAdr, // $67: Address-size override prefix
|
||
preLock,
|
||
preF2, // $F2: Repeat string/input/output or SIMD prefix
|
||
preF3, // $F3: Repeat string/input/output or SIMD prefix
|
||
oprDefault64, // In 64bit mode set default operand size to 64 (d64 note in Table A-x)
|
||
oprForce64, // In 64bit mode set operand size to 64 (f64 note in Table A-x)
|
||
flagVex,
|
||
flagEvex,
|
||
evexB, // Broadcast/RC/SAE Context (this is NOT a rexB extension)
|
||
evexV, // Extension of VEX.index
|
||
evexR, // rexR extension
|
||
evexX, // rexB extension (when no SIB present)
|
||
evexZ // Zeroing/Merging
|
||
);
|
||
TFlags = set of TFlag;
|
||
|
||
// Keep 8,16,32,64 together
|
||
TOperandSize = (os0, os8, os16, os32, os64, os48, os80, os128, os256, os512, os4096);
|
||
TAddressSize = (as16, as32, as64);
|
||
TRegisterType = (regNone, regGeneral, regGeneralH {upper half of general register}, regMm, regXmm, regSegment, regControl, regDebug, regX87, regFlags, regBounds, regInvalid);
|
||
TModRMType = (modReg, modMem);
|
||
TModRMTypes = set of TModRMType;
|
||
TSimdOpcode = (soInvalid, soNone, so66, soF2, soF3);
|
||
TSimdOpcodes = set of TSimdOpcode;
|
||
|
||
TInstructionFlag = (
|
||
ifOnly32, ifOnly64, ifOnlyVex,
|
||
ifPrefixLock, ifPrefixRep, ifPrefixRepE, ifPrefixRepNe
|
||
);
|
||
|
||
TOpCode = (
|
||
OPX_InternalUnknown,
|
||
OPX_Invalid,
|
||
OPX_InvalidX87, OPX_ReservedX87, OPX_Not87,
|
||
OPX_InvalidVex,
|
||
OPX_3dnow,
|
||
OPX_Group1a,
|
||
OPX_Group4,
|
||
OPX_Group5,
|
||
OPX_Group6,
|
||
OPX_Group7,
|
||
OPX_Group8,
|
||
OPX_Group9,
|
||
OPX_Group11,
|
||
OPX_Group12,
|
||
OPX_Group13,
|
||
OPX_Group14,
|
||
OPX_Group15,
|
||
OPX_Group16,
|
||
OPX_GroupP,
|
||
|
||
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, OPextract,
|
||
|
||
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, OPgetsec,
|
||
|
||
OPhadd, OPhlt, OPhreset, OPhsub,
|
||
|
||
OPidiv, OPimul, OPin, OPinc, OPincss, OPins, OPinsert, OPint, OPint1, OPint3,
|
||
OPinto, OPinvd, OPinvept, OPinvlpg, OPinvlpga, OPinvpcid, OPinvvpid, OPiret,
|
||
|
||
OPj__, OPjcxz, OPjecxz, OPjmp, OPjmpe, 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, OPmwait,
|
||
|
||
OPneg, OPnop, OPnot,
|
||
|
||
OPor, OPout, OPouts,
|
||
|
||
OPextrq,
|
||
|
||
OPpabs, OPpackssdw, OPpacksswb, OPpackusdw, OPpackuswb, OPpadd, OPpadds,
|
||
OPpaddus, OPpalignr, OPpand, OPpandn, OPpause, OPpavg, OPpavgusb, OPpblendvb,
|
||
OPpblend, 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, OPud0, OPud1, OPud2, OPumonitor, OPumwait, OPunpckh, OPunpckl,
|
||
|
||
OPvalign, OPvblendm, OPvbroadcast, OPvcompress, OPvcvtne2ps2bf16, OPvcvtneps2bf16,
|
||
OPvcvtph2ps, OPvcvtqq2, OPvcvtsd2usi, OPvcvtss2usi,
|
||
OPvcvttpd2, OPvcvttps2, OPvcvttsd2usi, OPvcvttss2usi, OPvcvtudq2, OPvcvtuqq2,
|
||
OPvcvtusi2, OPvdbpsadbw, OPvdpbf16ps, OPverr, OPverw, OPvexpand,
|
||
OPvfixupimm, OPvfmadd132, OPvfmadd213, OPvfmadd231, OPvfmaddsub132, OPvfmaddsub213,
|
||
OPvfmaddsub231, OPvfmsub132, OPvfmsub213, OPvfmsub231, OPvfmsubadd132,
|
||
OPvfmsubadd213, OPvfmsubadd231, OPvfnmadd132, OPvfnmadd213, OPvfnmadd231,
|
||
OPvfnmsub132, OPvfnmsub213, OPvfnmsub231, OPvfpclass, OPvgatherd, OPvgatherq,
|
||
OPvgetexp, OPvgetmant, OPvmaskmov, OPvmcall, OPvmclear, OPvmfunc,
|
||
OPvmgexit, OPvmlaunch, OPvmload, OPvmmcall, OPvmptrld, OPvmptrst, OPvmread,
|
||
OPvmresume, OPvmrun, OPvmsave, OPvmwrite, OPvmxoff, OPvmxon, OPvp2intersect,
|
||
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, OPvpmovs, OPvpmovus,
|
||
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,
|
||
// Conversion
|
||
OPSv_bw, OPSv_bd, OPSv_bq, OPSv_wd, OPSv_wq, OPSv_dq
|
||
);
|
||
|
||
TOpcodePrefix = (
|
||
OPPnone,
|
||
OPPv
|
||
);
|
||
|
||
TFullOpcode = record
|
||
Prefix: TOpcodePrefix;
|
||
Opcode: TOpcode;
|
||
Suffix: TOpcodeSuffix;
|
||
end;
|
||
|
||
TOperandFlag = (ofMemory);
|
||
TOperandFlags = set of TOperandFlag;
|
||
|
||
TInstructionOperand = record
|
||
CodeIndex: integer;
|
||
Value: String;
|
||
Size: TOperandSize;
|
||
ByteCount: Word;
|
||
ByteCount2: Byte;
|
||
FormatFlags: THexValueFormatFlags;
|
||
Flags: TOperandFlags;
|
||
end;
|
||
|
||
TInstruction = record
|
||
OpCode: TFullOpcode;
|
||
Flags: set of TInstructionFlag;
|
||
Segment: String;
|
||
MaskIndex: Byte;
|
||
|
||
Operand: array[1..4] of TInstructionOperand;
|
||
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;
|
||
Vex: record
|
||
Index: Byte;
|
||
VectorLength: TOperandSize;
|
||
MaskIndex: Byte;
|
||
end;
|
||
|
||
//--- result ---
|
||
Instruction: PInstruction;
|
||
|
||
//--- add operands ---
|
||
// the the Zz as used in AddZz routines are encoded according to:
|
||
//
|
||
// Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2:
|
||
// A.2 KEY TO ABBREVIATIONS
|
||
//
|
||
// and
|
||
//
|
||
// AMD64 Architecture Programmer’s Manual Volume 3:
|
||
// Appendix A Opcode and Operand Encodings
|
||
//
|
||
//---
|
||
procedure AddAp;
|
||
procedure AddBy;
|
||
procedure AddCd;
|
||
procedure AddDd;
|
||
procedure AddEb;
|
||
procedure AddEd;
|
||
procedure AddEp;
|
||
procedure AddEv;
|
||
procedure AddEw;
|
||
procedure AddEy;
|
||
procedure AddFv;
|
||
procedure AddGb;
|
||
procedure AddGd;
|
||
procedure AddGv;
|
||
procedure AddGw;
|
||
procedure AddGy;
|
||
procedure AddGz;
|
||
procedure AddHpd;
|
||
procedure AddHps;
|
||
procedure AddHsd;
|
||
procedure AddHss;
|
||
procedure AddHx;
|
||
procedure AddHq;
|
||
procedure AddHqq;
|
||
procedure AddIb;
|
||
procedure AddIv;
|
||
procedure AddIw;
|
||
procedure AddIz;
|
||
procedure AddJb;
|
||
procedure AddJz;
|
||
procedure AddLx;
|
||
procedure AddM;
|
||
procedure AddMa;
|
||
procedure AddMb;
|
||
procedure AddMd;
|
||
procedure AddMdq;
|
||
procedure AddMp;
|
||
procedure AddMps;
|
||
procedure AddMpd;
|
||
procedure AddMq;
|
||
procedure AddMs;
|
||
procedure AddMw;
|
||
procedure AddMw_Rv;
|
||
procedure AddMx;
|
||
procedure AddMy;
|
||
procedure AddNq;
|
||
procedure AddOb;
|
||
procedure AddOv;
|
||
procedure AddPd;
|
||
procedure AddPpi;
|
||
procedure AddPq;
|
||
procedure AddPy;
|
||
procedure AddQd;
|
||
procedure AddQpi;
|
||
procedure AddQq;
|
||
procedure AddRd;
|
||
procedure AddRd_Mb;
|
||
procedure AddRd_Mw;
|
||
procedure AddRd_q;
|
||
procedure AddRy;
|
||
procedure AddRy_Mb;
|
||
procedure AddRy_Mw;
|
||
procedure AddRv;
|
||
procedure AddSw;
|
||
procedure AddUdq;
|
||
procedure AddUdq_Md;
|
||
procedure AddUpd;
|
||
procedure AddUps;
|
||
procedure AddUq;
|
||
procedure AddUx;
|
||
procedure AddUx_Md;
|
||
procedure AddUx_Mq;
|
||
procedure AddUx_Mw;
|
||
procedure AddVdq;
|
||
procedure AddVpd;
|
||
procedure AddVps;
|
||
procedure AddVq;
|
||
procedure AddVqq;
|
||
procedure AddVsd;
|
||
procedure AddVss;
|
||
procedure AddVx;
|
||
procedure AddVy;
|
||
procedure AddWd;
|
||
procedure AddWdq;
|
||
procedure AddWpd;
|
||
procedure AddWps;
|
||
procedure AddWq;
|
||
procedure AddWqq;
|
||
procedure AddWsd;
|
||
procedure AddWss;
|
||
procedure AddWx;
|
||
procedure AddWx_Mq;
|
||
{$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 AddOpcReg(AType: TRegisterType; ASize: TOperandSize; AIndex: Byte);
|
||
procedure AddModReg(AType: TRegisterType; ASize: TOperandSize);
|
||
procedure AddModRM(AReqTypes: TModRMTypes; ASize: TOperandSize; AType: TRegisterType);
|
||
procedure AddVexReg(AType: TRegisterType; ASize: TOperandSize);
|
||
procedure AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Word=0; AFormatFlags: THexValueFormatFlags=[]; AFlags: TOperandFlags=[]; AByteCount2: Byte=0);
|
||
procedure AddOperand(const AValue: String; AByteCount: Word=0; AFormatFlags: THexValueFormatFlags=[]; AFlags: TOperandFlags=[]);
|
||
procedure AddStdOperands(AIndex: Byte);
|
||
|
||
procedure Check32;
|
||
procedure Check64;
|
||
procedure CheckVex;
|
||
procedure CheckLock;
|
||
procedure CheckRepeat;
|
||
procedure CheckRepeatX;
|
||
|
||
procedure ClearSIMDPrefix;
|
||
procedure DecodeSIMD(AValidClear: TSimdOpcodes = [soNone, so66, soF2, soF3]; ASizeOK: Boolean = False);
|
||
procedure DecodeModRM;
|
||
|
||
procedure Do2ByteOpcode;
|
||
procedure Do3ByteOpcode38;
|
||
procedure Do3ByteOpcode3A;
|
||
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 DoGroup17;
|
||
procedure DoGroupP;
|
||
procedure DoX87;
|
||
procedure DoVex(ASize: Byte);
|
||
|
||
function AddressSize: TAddressSize;
|
||
function HasOpcode: Boolean;
|
||
procedure SetOpcode(AOpcode: TOpcode; ASuffix: TOpCodeSuffix = OPSnone; APrefixV: Boolean = False);
|
||
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;
|
||
function VectorSize: TOperandSize;
|
||
|
||
function OPS_Wxx(AWIG, AW0, AW1: TOpCodeSuffix): TOpCodeSuffix;
|
||
function OPS_d_q: TOpCodeSuffix;
|
||
function OPS_ps_d: TOpCodeSuffix;
|
||
function OPS_ss_d: TOpCodeSuffix;
|
||
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);
|
||
function GetCodeMem: Pointer;
|
||
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
|
||
property CodeMem: Pointer read GetCodeMem;
|
||
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; out AnInfo: TDbgInstInfo); 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;
|
||
function IsAfterCallInstruction(AnAddress: TDBGPtr): boolean; override;
|
||
// Only Modify the values if result is true
|
||
function UnwindFrame(var AnAddress, AStackPtr, AFramePtr: TDBGPtr; AQuick: boolean; ARegisterValueList: TDbgRegisterValueList): boolean; override;
|
||
end;
|
||
|
||
{ TDbgStackUnwinderIntelDisAssembler }
|
||
|
||
TDbgStackUnwinderIntelDisAssembler = class(TDbgStackUnwinderX86Base)
|
||
private
|
||
//FCodeReadErrCnt: integer;
|
||
public
|
||
//procedure InitForThread(AThread: TDbgThread); override;
|
||
function Unwind(AFrameIndex: integer; var CodePointer, StackPointer,
|
||
FrameBasePointer: TDBGPtr; ACurrentFrame: TDbgCallstackEntry; out
|
||
ANewFrame: TDbgCallstackEntry): TTDbgStackUnwindResult; override;
|
||
end;
|
||
|
||
implementation
|
||
|
||
var
|
||
DBG_WARNINGS: PLazLoggerLogGroup;
|
||
|
||
const
|
||
ADDRESS_BYTES: array[TAddressSize] of Byte = (2, 4, 8);
|
||
OPERAND_BYTES: array[TOperandSize] of Word = (0, 1, 2, 4, 8, 6, 10, 16, 32, 64, 512);
|
||
OPERAND_BITS: array[TOperandSize] of Word = (0, 8, 16, 32, 64, 48, 80, 128, 256, 512, 4096);
|
||
ADDRESS_SIZE: array[TAddressSize] of TOperandSize = (os16, os32, os64);
|
||
REXOFFSET: array[Boolean] of Byte = (0, 8);
|
||
VEXOFFSET: array[Boolean] of Byte = (0, 16);
|
||
MODE_SIZE: array[TFPDMode] of TOperandSize = (os32, os64);
|
||
|
||
REG_A = 0;
|
||
REG_C = 1;
|
||
REG_D = 2;
|
||
REG_B = 3;
|
||
REG_SP = 4;
|
||
REG_BP = 5;
|
||
REG_SI = 6;
|
||
REG_DI = 7;
|
||
|
||
REG_ES = 0;
|
||
REG_CS = 1;
|
||
REG_SS = 2;
|
||
REG_DS = 3;
|
||
REG_FS = 4;
|
||
REG_GS = 5;
|
||
|
||
OPCODE_NAME: array [TOpCode] of String = (
|
||
'???', // OPX_InternalUnknown
|
||
'???',
|
||
'**x87**', '-x87-', '!x87!',
|
||
'**vex**',
|
||
'-3dnow-',
|
||
'**group1a**',
|
||
'**group4**',
|
||
'**group5**',
|
||
'**group6**',
|
||
'**group7**',
|
||
'**group8**',
|
||
'**group9**',
|
||
'**group11**',
|
||
'**group12**',
|
||
'**group13**',
|
||
'**group14**',
|
||
'**group15**',
|
||
'**group16**',
|
||
'**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', 'extract',
|
||
|
||
'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', 'getsec',
|
||
|
||
'hadd', 'hlt', 'hreset', 'hsub',
|
||
|
||
'idiv', 'imul', 'in', 'inc', 'incss', 'ins', 'insert', 'int', 'int1', 'int3',
|
||
'into', 'invd', 'invept', 'invlpg', 'invlpga', 'invpcid', 'invvpid', 'iret',
|
||
|
||
'j', 'jcxz', 'jecxz', 'jmp', 'jmpe', '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', 'mwait',
|
||
|
||
'neg', 'nop', 'not',
|
||
|
||
'or', 'out', 'outs',
|
||
|
||
'extrq',
|
||
|
||
'pabs', 'packssdw', 'packsswb', 'packusdw', 'packuswb', 'padd', 'padds',
|
||
'paddus', 'palignr', 'pand', 'pandn', 'pause', 'pavg', 'pavgusb', 'pblendvb',
|
||
'pblend', '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', 'ud0', 'ud1', 'ud2', 'umonitor', 'umwait', 'unpckh', 'unpckl',
|
||
|
||
'valign', 'vblendm', 'vbroadcast', 'vcompress', 'vcvtne2ps2bf16', 'vcvtneps2bf16',
|
||
'vcvtph2ps', 'vcvtqq2', 'vcvtsd2usi', 'vcvtss2usi',
|
||
'vcvttpd2', 'vcvttps2', 'vcvttsd2usi', 'vcvttss2usi', 'vcvtudq2', 'vcvtuqq2',
|
||
'vcvtusi2', 'vdbpsadbw', 'vdpbf16ps', 'verr', 'verw', 'vexpand',
|
||
'vfixupimm', 'vfmadd132', 'vfmadd213', 'vfmadd231', 'vfmaddsub132', 'vfmaddsub213',
|
||
'vfmaddsub231', 'vfmsub132', 'vfmsub213', 'vfmsub231', 'vfmsubadd132',
|
||
'vfmsubadd213', 'vfmsubadd231', 'vfnmadd132', 'vfnmadd213', 'vfnmadd231',
|
||
'vfnmsub132', 'vfnmsub213', 'vfnmsub231', 'vfpclass', 'vgatherd', 'vgatherq',
|
||
'vgetexp', 'vgetmant', 'vmaskmov', 'vmcall', 'vmclear', 'vmfunc',
|
||
'vmgexit', 'vmlaunch', 'vmload', 'vmmcall', 'vmptrld', 'vmptrst', 'vmread',
|
||
'vmresume', 'vmrun', 'vmsave', 'vmwrite', 'vmxoff', 'vmxon', 'vp2intersect',
|
||
'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', 'vpmovs', 'vpmovus', '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: 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',
|
||
//
|
||
'bw', 'bd', 'bq', 'wd', 'wq', 'dq'
|
||
);
|
||
OPCODE_PREFIX: array [TOpCodePrefix] of String = (
|
||
'', 'v'
|
||
);
|
||
|
||
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 = dm32) then
|
||
Include(Instruction^.Flags, ifOnly64);
|
||
end;
|
||
|
||
procedure TX86Disassembler.CheckVex;
|
||
begin
|
||
if not (flagVex in Flags)
|
||
then Include(Instruction^.Flags, ifOnlyVex);
|
||
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(AValidClear: TSimdOpcodes; ASizeOK: Boolean);
|
||
var
|
||
check: TFlags;
|
||
begin
|
||
if flagVex in Flags then Exit; // simd is part of the (e)vex prefix
|
||
|
||
check := Flags * [pre66, preF3, preF2];
|
||
if ASizeOK and (check <> [pre66]) // size prefix is allowed
|
||
then check := check - [pre66];
|
||
|
||
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 SimdOpcode in AValidClear
|
||
then Flags := Flags - check;
|
||
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; APrefixV: Boolean);
|
||
begin
|
||
if (flagVex in Flags) and APrefixV
|
||
then Instruction^.OpCode.Prefix := OPPv
|
||
else Instruction^.OpCode.Prefix := OPPnone;
|
||
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.HasOpcode: Boolean;
|
||
begin
|
||
Result := Instruction^.OpCode.Opcode <> OPX_InternalUnknown;
|
||
end;
|
||
|
||
function TX86Disassembler.OperandSize: TOperandSize;
|
||
begin
|
||
// effective AnInstruction.operand size
|
||
|
||
// Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 1:
|
||
// 3.6 OPERAND-SIZE AND ADDRESS-SIZE ATTRIBUTES
|
||
//
|
||
// Table 3-3 D-flag = 1 for 32 bit processes ->
|
||
// default 32, prefix 16
|
||
//
|
||
// Table 3-4
|
||
// REX.W 64, default 32, prefix 16 (REX.W overrules prefix)
|
||
//
|
||
// So for both dm32 and dm64 the default size is 32 unless overridden by flags
|
||
|
||
// A.3 ONE, TWO, AND THREE-BYTE Instruction^.Opcode MAPS
|
||
// Some instructions default or force to 64bit in dm64
|
||
|
||
if [oprForce64, rexW] * Flags <> []
|
||
then begin
|
||
Result := os64;
|
||
end
|
||
else begin
|
||
if pre66 in Flags
|
||
then Result := os16
|
||
else if oprDefault64 in Flags
|
||
then Result := os64
|
||
else Result := os32;
|
||
end;
|
||
end;
|
||
|
||
function TX86Disassembler.VectorSize: TOperandSize;
|
||
begin
|
||
if flagVex in Flags
|
||
then Result := Vex.VectorLength
|
||
else Result := os128;
|
||
end;
|
||
|
||
|
||
|
||
procedure TX86Disassembler.AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Word = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []; AByteCount2: Byte = 0);
|
||
var
|
||
idx: Byte;
|
||
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;
|
||
|
||
idx := CodeIdx;
|
||
if flagModRM in Flags then Inc(idx);
|
||
if flagSib in Flags then Inc(idx);
|
||
|
||
Instruction^.Operand[OperIdx].CodeIndex := idx;
|
||
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: Word = 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;
|
||
regBounds: begin
|
||
Result := Format('bnd%u', [AIndex]);
|
||
end;
|
||
else
|
||
Result := Format('**%u', [AIndex]);
|
||
end;
|
||
end;
|
||
|
||
function TX86Disassembler.OPS_Wxx(AWIG, AW0, AW1: TOpCodeSuffix): TOpCodeSuffix;
|
||
begin
|
||
if flagEvex in Flags
|
||
then begin
|
||
if rexW in Flags
|
||
then Result := AW1
|
||
else Result := AW0;
|
||
end
|
||
else Result := AWIG;
|
||
end;
|
||
|
||
function TX86Disassembler.OPS_d_q: TOpCodeSuffix;
|
||
const
|
||
MAP: array[Boolean] of TOpCodeSuffix = (OPSx_d, OPSx_q);
|
||
begin
|
||
Result := MAP[rexW in Flags];
|
||
end;
|
||
|
||
function TX86Disassembler.OPS_ps_d: TOpCodeSuffix;
|
||
const
|
||
MAP: array[Boolean] of TOpCodeSuffix = (OPSx_ps, OPSx_d);
|
||
begin
|
||
Result := MAP[rexW in Flags];
|
||
end;
|
||
|
||
function TX86Disassembler.OPS_ss_d: TOpCodeSuffix;
|
||
const
|
||
MAP: array[Boolean] of TOpCodeSuffix = (OPSx_ss, OPSx_d);
|
||
begin
|
||
Result := MAP[rexW in Flags];
|
||
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), ASize);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddOpcReg(AType: TRegisterType; ASize: TOperandSize; AIndex: Byte);
|
||
begin
|
||
AddReg(AType, ASize, AIndex + REXOFFSET[rexB in Flags] + VEXOFFSET[evexX in Flags]);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddModReg(AType: TRegisterType; ASize: TOperandSize);
|
||
begin
|
||
DecodeModRM;
|
||
AddReg(AType, ASize, ModRM.Index + REXOFFSET[rexR in Flags] + VEXOFFSET[evexR in Flags]);
|
||
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 + REXOFFSET[rexB in Flags] + VEXOFFSET[evexX in Flags])
|
||
else AddReg(regInvalid, ASize, ModRM.RM + REXOFFSET[rexB in Flags] + VEXOFFSET[evexX in Flags]);
|
||
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.AddVexReg(AType: TRegisterType; ASize: TOperandSize);
|
||
begin
|
||
if flagVex in Flags
|
||
then AddOperand(RegName(AType, ASize, Vex.Index + VEXOFFSET[evexV in Flags]), ASize)
|
||
else AddOperand(RegName(regInvalid, ASize, 0), ASize);
|
||
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.AddBy;
|
||
begin
|
||
if OperandSize = os64
|
||
then AddVexReg(regGeneral, os64)
|
||
else AddVexReg(regGeneral, os32);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddCd;
|
||
begin
|
||
AddModReg(regControl, MODE_SIZE[ProcessMode]);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddDd;
|
||
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.AddEp;
|
||
begin
|
||
case OperandSize of
|
||
os16: AddModRM([modReg, modMem], os32, regGeneral);
|
||
os32: AddModRM([modReg, modMem], os48, regGeneral);
|
||
os64: AddModRM([modReg, modMem], os80, regGeneral);
|
||
end;
|
||
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.AddHpd;
|
||
begin
|
||
if flagVex in Flags
|
||
then begin
|
||
if Vex.VectorLength = os128
|
||
then AddVexReg(regXmm, os128)
|
||
else AddVexReg(regXmm, os256);
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddHps;
|
||
begin
|
||
if flagVex in Flags
|
||
then begin
|
||
if Vex.VectorLength = os128
|
||
then AddVexReg(regXmm, os128)
|
||
else AddVexReg(regXmm, os256);
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddHsd;
|
||
begin
|
||
if flagVex in Flags
|
||
then AddVexReg(regXmm, os64);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddHss;
|
||
begin
|
||
if flagVex in Flags
|
||
then AddVexReg(regXmm, os32);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddHx;
|
||
begin
|
||
if flagVex in Flags
|
||
then AddVexReg(regXmm, Vex.VectorLength);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddHq;
|
||
begin
|
||
if flagVex in Flags
|
||
then AddVexReg(regXmm, os64);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddHqq;
|
||
begin
|
||
if flagVex in Flags
|
||
then begin
|
||
if Vex.VectorLength = os512
|
||
then AddVexReg(regXmm, os512)
|
||
else AddVexReg(regXmm, os256);
|
||
end;
|
||
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.AddLx;
|
||
var
|
||
idx: Byte;
|
||
n: Integer;
|
||
begin
|
||
// 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;
|
||
|
||
//@@@ todo: check, Instruction^.Operand[OperIdx].CodeIndex + ByteCount(2) should be the same as CodeIdx + idx;
|
||
idx := Code[CodeIdx + idx + 1] shr 4; // bit 7..4 -> reg
|
||
if ProcessMode = dm32
|
||
then idx := idx and $07;
|
||
|
||
AddOperand(RegName(regXmm, Vex.VectorLength, idx), Vex.VectorLength, 1);
|
||
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], VectorSize, regNone)
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddMp;
|
||
begin
|
||
if OperandSize = os16 //XXXX:XXXX
|
||
then AddModRM([modMem], os32, regNone)
|
||
else AddModRM([modMem], os48, regNone);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddMps;
|
||
begin
|
||
AddModRM([modMem], VectorSize, regNone)
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddMpd;
|
||
begin
|
||
AddModRM([modMem], VectorSize, 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;
|
||
begin
|
||
AddModRM([modMem], os16, 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.AddMx;
|
||
begin
|
||
if flagVex in Flags
|
||
then AddModRM([modMem], Vex.VectorLength, regXmm)
|
||
else AddModRM([modMem], os128, regXmm)
|
||
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.AddPd;
|
||
begin
|
||
AddModReg(regMm, os32);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddPpi;
|
||
begin
|
||
AddModReg(regMm, os64);
|
||
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.AddQpi;
|
||
begin
|
||
AddModRM([modReg, modMem], os64, regMm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddQq;
|
||
begin
|
||
AddModRM([modReg, modMem], os64, regMm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddRd;
|
||
begin
|
||
AddModRM([modReg], MODE_SIZE[ProcessMode], regGeneral);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddRd_Mb;
|
||
begin
|
||
DecodeModRM;
|
||
|
||
if ModRM.Mode = 3 // reg
|
||
then AddModRM([modReg], os32, regGeneral)
|
||
else AddModRM([modMem], os8, regNone);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddRd_Mw;
|
||
begin
|
||
DecodeModRM;
|
||
|
||
if ModRM.Mode = 3 // reg
|
||
then AddModRM([modReg], os32, regGeneral)
|
||
else AddModRM([modMem], os16, regNone);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddRd_q;
|
||
begin
|
||
AddModRM([modReg], MODE_SIZE[ProcessMode], regGeneral);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddRy;
|
||
begin
|
||
if OperandSize = os64
|
||
then AddModRM([modReg], os64, regGeneral)
|
||
else AddModRM([modReg], os32, regGeneral);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddRy_Mb;
|
||
begin
|
||
if ModRM.Mode = 3 // reg
|
||
then AddModRM([modReg], OperandSize, regGeneral)
|
||
else AddModRM([modMem], os8, regNone);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddRy_Mw;
|
||
begin
|
||
if ModRM.Mode = 3 // reg
|
||
then AddModRM([modReg], OperandSize, regGeneral)
|
||
else AddModRM([modMem], os16, regNone);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddRv;
|
||
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.AddUdq_Md;
|
||
begin
|
||
if ModRM.Mode = 3 // reg
|
||
then AddModRM([modReg], os128, regXmm)
|
||
else AddModRM([modMem], os32, regNone);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddUpd;
|
||
begin
|
||
AddModRM([modReg], VectorSize, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddUps;
|
||
begin
|
||
AddModRM([modReg], VectorSize, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddUq;
|
||
begin
|
||
AddModRM([modReg], os64, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddUx;
|
||
begin
|
||
if flagVex in Flags
|
||
then AddModRM([modReg], Vex.VectorLength, regXmm)
|
||
else AddModRM([modReg], os128, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddUx_Md;
|
||
var
|
||
Size: TOperandSize;
|
||
begin
|
||
if ModRM.Mode = 3 // reg
|
||
then begin
|
||
case Vex.VectorLength of
|
||
os512: Size := os256;
|
||
else
|
||
Size := os128;
|
||
end;
|
||
|
||
AddModRM([modReg], Size, regXmm);
|
||
end
|
||
else
|
||
begin
|
||
case Vex.VectorLength of
|
||
os128: Size := os32;
|
||
os256: Size := os64;
|
||
os512: Size := os128;
|
||
else
|
||
Size := os32;
|
||
end;
|
||
|
||
AddModRM([modMem], Size, regNone);
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddUx_Mq;
|
||
var
|
||
Size: TOperandSize;
|
||
begin
|
||
if ModRM.Mode = 3 // reg
|
||
then begin
|
||
case Vex.VectorLength of
|
||
os512: Size := os256;
|
||
else
|
||
Size := os128;
|
||
end;
|
||
|
||
AddModRM([modReg], Size, regXmm);
|
||
end
|
||
else
|
||
begin
|
||
case Vex.VectorLength of
|
||
os128: Size := os64;
|
||
os256: Size := os128;
|
||
os512: Size := os256;
|
||
else
|
||
Size := os64;
|
||
end;
|
||
|
||
AddModRM([modMem], Size, regNone);
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddUx_Mw;
|
||
var
|
||
Size: TOperandSize;
|
||
begin
|
||
if ModRM.Mode = 3 // reg
|
||
then begin
|
||
case Vex.VectorLength of
|
||
os512: Size := os256;
|
||
else
|
||
Size := os128;
|
||
end;
|
||
|
||
AddModRM([modReg], Size, regXmm);
|
||
end
|
||
else
|
||
begin
|
||
case Vex.VectorLength of
|
||
os128: Size := os16;
|
||
os256: Size := os32;
|
||
os512: Size := os64;
|
||
else
|
||
Size := os16;
|
||
end;
|
||
|
||
AddModRM([modMem], Size, regNone);
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVdq;
|
||
begin
|
||
AddModReg(regXmm, VectorSize);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVpd;
|
||
begin
|
||
AddModReg(regXmm, VectorSize);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVps;
|
||
begin
|
||
AddModReg(regXmm, VectorSize);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVq;
|
||
begin
|
||
AddModReg(regXmm, os128);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVqq;
|
||
begin
|
||
if Vex.VectorLength = os512
|
||
then AddModReg(regXmm, os512)
|
||
else AddModReg(regXmm, os256);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVsd;
|
||
begin
|
||
AddModReg(regXmm, os64);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVss;
|
||
begin
|
||
AddModReg(regXmm, os32);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVx;
|
||
begin
|
||
if flagVex in Flags
|
||
then AddModReg(regXmm, Vex.VectorLength)
|
||
else AddModReg(regXmm, os128)
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddVy;
|
||
begin
|
||
if OperandSize = os64
|
||
then AddModReg(regXmm, os64)
|
||
else AddModReg(regXmm, os32);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWd;
|
||
begin
|
||
AddModRM([modReg, modMem], os32, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWdq;
|
||
begin
|
||
AddModRM([modReg, modMem], VectorSize, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWpd;
|
||
begin
|
||
AddModRM([modReg, modMem], VectorSize, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWps;
|
||
begin
|
||
AddModRM([modReg, modMem], VectorSize, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWq;
|
||
begin
|
||
AddModRM([modReg, modMem], os64, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWqq;
|
||
begin
|
||
if Vex.VectorLength = os512
|
||
then AddModRM([modReg, modMem], os512, regXmm)
|
||
else AddModRM([modReg, modMem], os256, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWsd;
|
||
begin
|
||
AddModRM([modReg, modMem], os64, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWss;
|
||
begin
|
||
AddModRM([modReg, modMem], os32, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWx;
|
||
begin
|
||
AddModRM([modReg, modMem], VectorSize, regXmm);
|
||
end;
|
||
|
||
procedure TX86Disassembler.AddWx_Mq;
|
||
begin
|
||
DecodeModRM;
|
||
AddUx_Mq;
|
||
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, REG_A); AddIb; end;
|
||
5: begin AddReg(regGeneral, OperandSize, REG_A); 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
|
||
Assert(Code[CodeIdx] in [$80..$83,$8F], 'Not group 1');
|
||
|
||
DecodeModRM;
|
||
|
||
// group 1a
|
||
if Code[CodeIdx] = $8F
|
||
then begin
|
||
Default64;
|
||
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
|
||
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
|
||
Assert(Code[CodeIdx] in [$C0, $C1, $D0..$D3], 'Not group 2');
|
||
|
||
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; AddReg(regGeneral, os8, REG_C); end;
|
||
$D3: begin AddEv; AddReg(regGeneral, os8, REG_C); end;
|
||
else
|
||
Exit;
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup3;
|
||
const
|
||
OPC: array[0..7] of TOpCode = (OPtest, OPtest, OPnot, OPneg, OPmul, OPimul, OPdiv, OPidiv);
|
||
begin
|
||
Assert(Code[CodeIdx] in [$F6,$F7], 'Not group 3');
|
||
|
||
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;
|
||
end;
|
||
if ModRM.Index in [2, 3]
|
||
then CheckLock;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup4;
|
||
begin
|
||
Assert(Code[CodeIdx] = $FE, 'Not group 4');
|
||
|
||
DecodeModRM;
|
||
|
||
case ModRM.Index of
|
||
0: SetOpcode(OPinc);
|
||
1: SetOpcode(OPdec);
|
||
else
|
||
SetOpcode(OPX_Group4);
|
||
Exit;
|
||
end;
|
||
AddEb;
|
||
CheckLock;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup5;
|
||
begin
|
||
Assert(Code[CodeIdx] = $FF, 'Not group 5');
|
||
|
||
DecodeModRM;
|
||
|
||
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); AddEp; 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
|
||
Assert(Code[CodeIdx] = $00, 'Not group 6');
|
||
|
||
DecodeModRM;
|
||
|
||
case ModRM.Index of
|
||
0: begin SetOpcode(OPsldt); AddMw_Rv; end;
|
||
1: begin SetOpcode(OPstr); AddMw_Rv; end;
|
||
2: begin SetOpcode(OPlldt); AddEw; end;
|
||
3: begin SetOpcode(OPltr); AddEw; end;
|
||
4: begin SetOpcode(OPverr); AddEw; end;
|
||
5: begin SetOpcode(OPverw); AddEw; end;
|
||
else
|
||
SetOpcode(OPX_Group6);
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup7;
|
||
|
||
{
|
||
Intel and AMD have their own (nonoverlapping) instructions in this group.
|
||
Decoding is based on:
|
||
|
||
Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2:
|
||
Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group Number
|
||
|
||
AMD64 Architecture Programmer’s Manual Volume 3:
|
||
Table A-7. ModRM.reg Extensions for the Secondary Opcode Map
|
||
and
|
||
Table A-8. Opcode 01h ModRM Extensions
|
||
}
|
||
|
||
const
|
||
RM0: array [0..7] of TOpCode = (OPX_Group7, OPvmcall, OPvmlaunch, OPvmresume, OPvmxoff, OPX_Group7, OPX_Group7, OPX_Group7);
|
||
RM1: array [0..7] of TOpCode = (OPmonitor, OPmwait, OPclac, OPstac, OPX_Group7, OPX_Group7, OPX_Group7, OPencls);
|
||
RM2: array [0..7] of TOpCode = (OPgetbv, OPsetbv, OPX_Group7, OPX_Group7, OPvmfunc, OPxend, OPxtest, OPenclu);
|
||
RM3: array [0..7] of TOpCode = (OPvmrun, OPvmmcall, OPvmload, OPvmsave, OPstgi, OPclgi, OPskinit, OPinvlpga);
|
||
begin
|
||
Assert(Code[CodeIdx] = $01, 'Not group 7');
|
||
|
||
DecodeModRM;
|
||
|
||
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
|
||
Assert(Code[CodeIdx] = $BA, 'Not group 8');
|
||
|
||
DecodeModRM;
|
||
|
||
if ModRM.Index < 4
|
||
then SetOpcode(OPX_Group8)
|
||
else SetOpcode(RM8[ModRM.Index]);
|
||
AddEv; AddIb;
|
||
|
||
if ModRM.Index in [5..7]
|
||
then CheckLock;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup9;
|
||
begin
|
||
Assert(Code[CodeIdx] = $C7, 'Not group 9');
|
||
|
||
DecodeModRM;
|
||
|
||
SetOpcode(OPX_Group9);
|
||
case ModRM.Index of
|
||
1: begin
|
||
DecodeSIMD([soNone]);
|
||
if SimdOpcode = soNone
|
||
then begin
|
||
if OperandSize = os64
|
||
then begin
|
||
SetOpcode(OPcmpxchg, OPSx_16b);
|
||
AddMdq;
|
||
end
|
||
else begin
|
||
SetOpcode(OPcmpxchg, OPSx_8b);
|
||
AddMq;
|
||
end;
|
||
CheckLock;
|
||
end;
|
||
end;
|
||
6: begin
|
||
if ModRM.Mode = 3
|
||
then begin
|
||
DecodeSIMD([soNone]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPrdrand); AddRv; end;
|
||
end;
|
||
end
|
||
else begin
|
||
DecodeSIMD([soNone, so66, soF3]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPvmptrld); AddMq; end;
|
||
so66: begin SetOpcode(OPvmclear); AddMq; end;
|
||
soF3: begin SetOpcode(OPvmxon); AddMq; end;
|
||
end;
|
||
end;
|
||
end;
|
||
7: begin
|
||
if ModRM.Mode = 3
|
||
then begin
|
||
DecodeSIMD([soNone, soF3]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPrdseed); AddRv; end;
|
||
soF3: begin SetOpcode(OPrdpid); AddRd_q; end;
|
||
end;
|
||
end
|
||
else begin
|
||
DecodeSIMD([soNone]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPvmptrst); AddMq; end;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup10;
|
||
begin
|
||
Assert(Code[CodeIdx] = $B9, 'Not group 10');
|
||
|
||
DecodeModRM;
|
||
|
||
SetOpcode(OPud1);
|
||
AddGv;AddEv;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup11;
|
||
begin
|
||
Assert(Code[CodeIdx] in [$C6,$C7], 'Not group 11');
|
||
|
||
DecodeModRM;
|
||
|
||
SetOpcode(OPX_Group11);
|
||
|
||
case ModRM.Index of
|
||
0: begin
|
||
case Code[CodeIdx] of
|
||
$C6: begin SetOpcode(OPmov); AddEb; AddIb; end;
|
||
$C7: begin SetOpcode(OPmov); AddEv; AddIz; end;
|
||
end;
|
||
end;
|
||
7: begin
|
||
if (ModRm.Mode = 3) and (ModRM.RM = 0)
|
||
then begin
|
||
case Code[CodeIdx] of
|
||
$C6: begin SetOpcode(OPxabort); AddIb; end;
|
||
$C7: begin SetOpcode(OPxbegin); AddJz; end;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
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
|
||
Assert(Code[CodeIdx] = $71, 'Not group 12');
|
||
|
||
DecodeModRM;
|
||
|
||
DecodeSIMD([soNone, so66]);
|
||
if (SimdOpcode in [soNone, so66]) and (OPC[ModRM.Index] <> OPX_Invalid)
|
||
then begin
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPC[ModRM.Index], OPSx_w ); AddNq; AddIb; end;
|
||
so66: begin SetOpcode(OPC[ModRM.Index], OPSx_w, True); AddHx; AddUx; 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
|
||
Assert(Code[CodeIdx] = $72, 'Not group 13');
|
||
|
||
DecodeModRM;
|
||
|
||
DecodeSIMD([soNone, so66]);
|
||
if (SimdOpcode in [soNone, so66]) and (OPC[ModRM.Index] <> OPX_Invalid)
|
||
then begin
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPC[ModRM.Index], OPSx_d ); AddNq; AddIb; end;
|
||
so66: begin SetOpcode(OPC[ModRM.Index], OPSx_d, True); AddHx; AddUx; 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, OPpsll);
|
||
OPS: array[0..7] of TOpCodeSuffix = (OPSnone, OPSnone, OPSx_q, OPSx_dq, OPSnone, OPSnone, OPSx_q, OPSx_dq);
|
||
begin
|
||
Assert(Code[CodeIdx] = $73, 'Not group 14');
|
||
|
||
DecodeModRM;
|
||
SetOpcode(OPX_Group14);
|
||
|
||
if OPC[ModRM.Index] <> OPX_Invalid
|
||
then begin
|
||
DecodeSIMD([soNone, so66]);
|
||
|
||
SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]);
|
||
|
||
case SimdOpcode of
|
||
soNone: begin
|
||
if ModRM.Index in [2,6]
|
||
then begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index]); AddNq; AddIb; end;
|
||
end;
|
||
so66: begin SetOpcode(OPC[ModRM.Index], OPS[ModRM.Index], True); AddHx; AddUx; AddIb; end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup15;
|
||
begin
|
||
Assert(Code[CodeIdx] = $AE, 'Not group 15');
|
||
|
||
DecodeModRM;
|
||
DecodeSIMD([soNone, soF3]);
|
||
|
||
SetOpcode(OPX_Group15);
|
||
|
||
case SimdOpcode of
|
||
soNone: begin
|
||
if ModRM.Mode = 3
|
||
then begin
|
||
case ModRM.Index of
|
||
5: begin SetOpcode(OPlfence); end;
|
||
6: begin SetOpcode(OPmfence); end;
|
||
7: begin SetOpcode(OPsfence); end
|
||
end;
|
||
end
|
||
else begin
|
||
//@@@ check rex -> xsave64
|
||
case ModRM.Index of
|
||
0: begin SetOpcode(OPfxsave ); AddModRM([modMem], os4096, regNone); end;
|
||
1: begin SetOpcode(OPfxrstor ); AddModRM([modMem], os4096, regNone); end;
|
||
2: begin SetOpcode(OPldmxcsr, OPSnone, True); AddMd; end;
|
||
3: begin SetOpcode(OPstmxcsr, OPSnone, True); AddMd; end;
|
||
4: begin SetOpcode(OPxsave ); AddModRM([modMem], os4096, regNone); end; // the data is variable in size.
|
||
5: begin SetOpcode(OPxrstor ); AddModRM([modMem], os4096, regNone); end; // the first 512 bytes are the same as fxsave
|
||
6: begin SetOpcode(OPxsaveopt ); AddModRM([modMem], os4096, regNone); end; //
|
||
7: begin SetOpcode(OPclflush ); AddMb; end
|
||
end;
|
||
end;
|
||
end;
|
||
soF3: begin
|
||
if ModRM.Mode = 3
|
||
then begin
|
||
case ModRM.Index of
|
||
0: begin SetOpcode(OPrdfsbase); AddRy; end;
|
||
1: begin SetOpcode(OPrdgsbase); AddRy; end;
|
||
2: begin SetOpcode(OPwrfsbase); AddRy; end;
|
||
3: begin SetOpcode(OPwrgsbase); AddRy; end;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup16;
|
||
const
|
||
OPS: array[0..3] of TOpCodeSuffix = (OPSp_nta, OPSp_t0, OPSp_t1, OPSp_t2);
|
||
begin
|
||
Assert(Code[CodeIdx] = $18, 'Not group 16');
|
||
|
||
DecodeModRM;
|
||
|
||
if (ModRM.Mode <> 3) and (ModRM.Index < 4)
|
||
then begin
|
||
SetOpcode(OPprefetch, OPS[ModRM.Index]);
|
||
AddMb;
|
||
end
|
||
else SetOpcode(OPnop);
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroup17;
|
||
begin
|
||
Assert(Code[CodeIdx] = $F3, 'Not group 17');
|
||
|
||
DecodeModRM;
|
||
|
||
case ModRM.Index of
|
||
1: SetOpcode(OPblsr);
|
||
2: SetOpcode(OPblsmsk);
|
||
3: SetOpcode(OPblsi);
|
||
else
|
||
Exit;
|
||
end;
|
||
CheckVex;
|
||
AddBy; AddEy;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoGroupP;
|
||
begin
|
||
Assert(Code[CodeIdx] = $0D, 'Not group P');
|
||
|
||
DecodeModRM;
|
||
|
||
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
|
||
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
|
||
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
|
||
Check64;
|
||
SetOpcode(OPsyscall);
|
||
end;
|
||
$06: begin
|
||
SetOpcode(OPclts);
|
||
end;
|
||
$07: begin
|
||
Check64;
|
||
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;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmovu, OPSx_ps, True); AddVps; AddWps; end;
|
||
so66: begin SetOpcode(OPmovu, OPSx_pd, True); AddVpd; AddWpd; end;
|
||
soF2: begin
|
||
DecodeModRM;
|
||
if ModRM.Mode = 3
|
||
then begin SetOpcode(OPmov, OPSx_sd, True); AddVx; AddHx; AddWsd; end
|
||
else begin SetOpcode(OPmov, OPSx_sd, True); AddVx; AddWsd; end;
|
||
end;
|
||
soF3: begin
|
||
DecodeModRM;
|
||
if ModRM.Mode = 3
|
||
then begin SetOpcode(OPmov, OPSx_ss, True); AddVx; AddHx; AddWss; end
|
||
else begin SetOpcode(OPmov, OPSx_ss, True); AddVx; AddWss; end;
|
||
end;
|
||
end;
|
||
end;
|
||
$11: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmovu, OPSx_ps, True); AddWps; AddVps; end;
|
||
so66: begin SetOpcode(OPmovu, OPSx_pd, True); AddWpd; AddVpd; end;
|
||
soF2: begin
|
||
DecodeModRM;
|
||
if ModRM.Mode = 3
|
||
then begin SetOpcode(OPmov, OPSx_sd, True); AddWsd; AddHx; AddVsd; end
|
||
else begin SetOpcode(OPmov, OPSx_sd, True); AddWsd; AddVsd; end;
|
||
end;
|
||
soF3: begin
|
||
DecodeModRM;
|
||
if ModRM.Mode = 3
|
||
then begin SetOpcode(OPmov, OPSx_ss, True); AddWss; AddHx; AddVss; end
|
||
else begin SetOpcode(OPmov, OPSx_ss, True); AddWss; AddVss; end;
|
||
end;
|
||
end;
|
||
end;
|
||
$12: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin
|
||
DecodeModRM;
|
||
if ModRM.Mode = 3
|
||
then begin SetOpcode(OPmovhlps, OPSnone, True); AddVq; AddHq; AddUq end
|
||
else begin SetOpcode(OPmovl, OPSx_ps, True); AddVq; AddHq; AddMq end;
|
||
end;
|
||
so66: begin SetOpcode(OPmovl, OPSx_pd, True); AddVq; AddHq; AddMq; end;
|
||
soF2: begin SetOpcode(OPmovddup, OPSnone, True); AddVx; AddWx; end;
|
||
soF3: begin SetOpcode(OPmovsldup, OPSnone, True); AddVx; AddWx; end;
|
||
end;
|
||
end;
|
||
$13: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmovl, OPSx_ps, True); AddMq; AddVps; end;
|
||
so66: begin SetOpcode(OPmovl, OPSx_pd, True); AddMq; AddVsd; end;
|
||
end;
|
||
end;
|
||
$14: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPunpckl, OPSx_ps, True); AddVx; AddHx; AddWx; end;
|
||
so66: begin SetOpcode(OPunpckl, OPSx_pd, True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$15: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPunpckh, OPSx_ps, True); AddVx; AddHx; AddWx; end;
|
||
so66: begin SetOpcode(OPunpckh, OPSx_pd, True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$16: begin
|
||
DecodeSIMD([soNone, so66, soF3]);
|
||
case SimdOpcode of
|
||
soNone: begin
|
||
DecodeModRM;
|
||
if ModRM.Mode = 3
|
||
then begin SetOpcode(OPmovlh, OPSx_ps, True); AddVdq; AddHq; AddUq end
|
||
else begin SetOpcode(OPmovh, OPSx_ps, True); AddVdq; AddHq; AddMq end;
|
||
end;
|
||
so66: begin SetOpcode(OPmovh, OPSx_pd, True); AddVdq; AddHq; AddMq end;
|
||
soF3: begin SetOpcode(OPmovshdup, OPSnone, True); AddVx; AddWx; end;
|
||
end;
|
||
end;
|
||
$17: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmovh, OPSx_ps, True); AddMq; AddVq; end;
|
||
so66: begin SetOpcode(OPmovh, OPSx_pd, True); AddMq; AddVq; end;
|
||
end;
|
||
end;
|
||
$18: begin
|
||
DoGroup16;
|
||
end;
|
||
$19: begin
|
||
SetOpcode(OPnop);
|
||
AddEv;
|
||
end;
|
||
$1A: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPbndldx); AddModReg(regBounds, os128); AddModRM([ modMem], os128, regBounds); end;
|
||
so66: begin SetOpcode(OPbndmov); AddModReg(regBounds, os128); AddModRM([modReg, modMem], os128, regBounds); end;
|
||
soF2: begin SetOpcode(OPbndcu ); AddModReg(regBounds, os128); AddModRM([modReg, modMem], os128, regBounds); end;
|
||
soF3: begin SetOpcode(OPbndcl ); AddModReg(regBounds, os128); AddModRM([modReg, modMem], os128, regBounds); end;
|
||
end;
|
||
end;
|
||
$1B: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPbndstx); AddModRM([ modMem], os128, regBounds); AddModReg(regBounds, os128); end;
|
||
so66: begin SetOpcode(OPbndmov); AddModRM([modReg, modMem], os128, regBounds); AddModReg(regBounds, os128); end;
|
||
soF2: begin SetOpcode(OPbndmk ); AddModReg(regBounds, os128); AddModRM([ modMem], os128, regBounds); end;
|
||
soF3: begin SetOpcode(OPbndcn ); AddModReg(regBounds, os128); AddModRM([modReg, modMem], os128, regBounds); end;
|
||
end;
|
||
end;
|
||
$1C..$1D: begin
|
||
SetOpcode(OPnop);
|
||
AddEv;
|
||
end;
|
||
$1E: begin
|
||
DecodeSIMD([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; AddCd;
|
||
end;
|
||
$21: begin
|
||
SetOpcode(OPmov);
|
||
AddRd; AddDd;
|
||
end;
|
||
$22: begin
|
||
SetOpcode(OPmov);
|
||
AddCd; AddRd;
|
||
end;
|
||
$23: begin
|
||
SetOpcode(OPmov);
|
||
AddDd; AddRd;
|
||
end;
|
||
// $24..$27: OPX_Invalid
|
||
$28: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmova, OPSx_ps, True); AddVps; AddWps; end;
|
||
so66: begin SetOpcode(OPmova, OPSx_pd, True); AddVpd; AddWpd; end;
|
||
end;
|
||
end;
|
||
$29: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmova, OPSx_ps, True); AddWps; AddVps; end;
|
||
so66: begin SetOpcode(OPmova, OPSx_pd, True); AddWpd; AddVpd; end;
|
||
end;
|
||
end;
|
||
$2A: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPcvtpi2, OPSx_ps ); AddVps; AddQpi; end;
|
||
so66: begin SetOpcode(OPcvtpi2, OPSx_pd ); AddVpd; AddQpi; end;
|
||
soF2: begin SetOpcode(OPcvtsi2, OPSx_sd, True); AddVsd; AddHsd; AddEy; end;
|
||
soF3: begin SetOpcode(OPcvtsi2, OPSx_ss, True); AddVss; AddHss; AddEy; end;
|
||
end;
|
||
end;
|
||
$2B: begin
|
||
DecodeSIMD([soNone, so66, soF2, soF3]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmovnt, OPSx_ps, True); AddMps; AddVps; end;
|
||
so66: begin SetOpcode(OPmovnt, OPSx_pd, True); AddMpd; AddVpd; end;
|
||
soF2: begin SetOpcode(OPmovnt, OPSx_sd, True); AddMpd; AddVpd; end;
|
||
soF3: begin SetOpcode(OPmovnt, OPSx_ss, True); AddMpd; AddVpd; end;
|
||
end;
|
||
end;
|
||
$2C: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPcvttps2, OPSx_pi ); AddPpi; AddWps; end;
|
||
so66: begin SetOpcode(OPcvttpd2, OPSx_pi ); AddPpi; AddWpd; end;
|
||
soF2: begin SetOpcode(OPcvttsd2, OPSx_si, True); AddGy; AddWsd; end;
|
||
soF3: begin SetOpcode(OPcvttss2, OPSx_si, True); AddGy; AddWss; end;
|
||
end;
|
||
end;
|
||
$2D: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPcvtps2, OPSx_pi ); AddPpi; AddWps; end;
|
||
so66: begin SetOpcode(OPcvtpd2, OPSx_pi ); AddPpi; AddWpd; end;
|
||
soF2: begin SetOpcode(OPcvtsd2, OPSx_si, True); AddGy; AddWsd; end;
|
||
soF3: begin SetOpcode(OPcvtss2, OPSx_si, True); AddGy; AddWss; end;
|
||
end;
|
||
end;
|
||
$2E: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPucomi, OPSx_ss, True); AddVss; AddWss; end;
|
||
so66: begin SetOpcode(OPucomi, OPSx_sd, True); AddVsd; AddWsd; end;
|
||
end;
|
||
end;
|
||
$2F: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPcomi, OPSx_ss, True); AddVss; AddWss; end;
|
||
so66: begin SetOpcode(OPcomi, OPSx_sd, True); 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: OPX_Invalid
|
||
$37: begin
|
||
SetOpcode(OPgetsec);
|
||
end;
|
||
$38: begin
|
||
Inc(CodeIdx);
|
||
Inc(ModRMIdx);
|
||
Do3ByteOpcode38;
|
||
end;
|
||
// $39: OPX_Invalid
|
||
$3A: begin
|
||
Inc(CodeIdx);
|
||
Inc(ModRMIdx);
|
||
Do3ByteOpcode3A;
|
||
end;
|
||
// $3B..$3F: OPX_Invalid
|
||
//---
|
||
$40..$4F: begin
|
||
SetOpcode(OPcmov__, StdCond(Code[CodeIdx]));
|
||
AddGv; AddEv;
|
||
end;
|
||
//---
|
||
$50: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmovmsk, OPSx_ps, True); AddGy; AddUps; end;
|
||
so66: begin SetOpcode(OPmovmsk, OPSx_pd, True); AddGy; AddUpd; end;
|
||
end;
|
||
end;
|
||
$51..$53: begin
|
||
case Code[CodeIdx] of
|
||
$52: ValidSimd := [soNone, soF3];
|
||
$53: ValidSimd := [soNone, soF3];
|
||
else
|
||
ValidSimd := [soNone, so66, soF2, soF3];
|
||
end;
|
||
DecodeSIMD(ValidSimd);
|
||
|
||
if SimdOpcode in ValidSimd
|
||
then begin
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_ps, True); AddVps; AddWps; end;
|
||
so66: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_pd, True); AddVpd; AddWpd; end;
|
||
soF2: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_sd, True); AddVsd; AddHsd; AddWsd; end;
|
||
soF3: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_ss, True); AddVss; AddHss; AddWss; end;
|
||
end;
|
||
end;
|
||
end;
|
||
$54..$59, $5C..$5F: begin
|
||
case Code[CodeIdx] of
|
||
$54: ValidSimd := [soNone, so66];
|
||
$55: ValidSimd := [soNone, so66];
|
||
$56: ValidSimd := [soNone, so66];
|
||
$57: ValidSimd := [soNone, so66];
|
||
else
|
||
ValidSimd := [soNone, so66, soF2, soF3];
|
||
end;
|
||
DecodeSIMD(ValidSimd);
|
||
|
||
if SimdOpcode in ValidSimd
|
||
then begin
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_ps, True); AddVps; AddHps; AddWps; end;
|
||
so66: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_pd, True); AddVpd; AddHpd; AddWpd; end;
|
||
soF2: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_sd, True); AddVsd; AddHsd; AddWsd; end;
|
||
soF3: begin SetOpcode(OPC_5x[Code[CodeIdx] and $F], OPSx_ss, True); AddVss; AddHss; AddWss; end;
|
||
end;
|
||
end;
|
||
end;
|
||
$5A: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPcvtps2, OPSx_pd, True); AddVpd; AddWps; end;
|
||
so66: begin SetOpcode(OPcvtpd2, OPSx_ps, True); AddVps; AddWpd; end;
|
||
soF2: begin SetOpcode(OPcvtsd2, OPSx_ss, True); AddVss; AddHx; AddWsd; end;
|
||
soF3: begin SetOpcode(OPcvtss2, OPSx_sd, True); AddVsd; AddHx; AddWss; end;
|
||
end;
|
||
end;
|
||
$5B: begin
|
||
DecodeSIMD([soNone, so66, soF3]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPcvtdq2, OPSx_ps, True); AddVps; AddWdq; end;
|
||
so66: begin SetOpcode(OPcvtps2, OPSx_dq, True); AddVdq; AddWps; end;
|
||
soF3: begin SetOpcode(OPcvttps2, OPSx_dq, True); AddVdq; AddWps; end;
|
||
end;
|
||
end;
|
||
// $5C..$5F: see $54
|
||
//---
|
||
$60..$6B: begin
|
||
idx := Code[CodeIdx] and $F;
|
||
DecodeSIMD([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], True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$6C..$6D: begin
|
||
idx := Code[CodeIdx] and $F;
|
||
DecodeSIMD([so66]);
|
||
if SimdOpcode = so66
|
||
then begin SetOpcode(OPC_6x[idx], OPS_6x[idx], True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
$6E: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmov, OPS_d_q ); AddPd; AddEy; end;
|
||
so66: begin SetOpcode(OPmov, OPS_d_q, True); AddVy; AddEy; end;
|
||
end;
|
||
end;
|
||
$6F: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmov, OPSx_q ); AddPq; AddQq; end;
|
||
so66: begin SetOpcode(OPmov, OPS_Wxx(OPSx_dqa, OPSx_dqa32, OPSx_dqa64), True); AddVx; AddWx; end;
|
||
soF2: begin SetOpcode(OPmov, OPS_Wxx(OPSx_dqu, OPSx_dqu8, OPSx_dqu16), True); AddVx; AddWx; end;
|
||
soF3: begin SetOpcode(OPmov, OPS_Wxx(OPSx_dqu, OPSx_dqu32, OPSx_dqu64), True); AddVx; AddWx; end;
|
||
end;
|
||
end;
|
||
//---
|
||
$70: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPpshuf, OPSx_w ); AddPq; AddQq; AddIb; end;
|
||
so66: begin SetOpcode(OPpshuf, OPSx_d, True); AddVx; AddWx; AddIb; end;
|
||
soF2: begin SetOpcode(OPpshuf, OPSx_lw, True); AddVx; AddWx; AddIb; end;
|
||
soF3: begin SetOpcode(OPpshuf, OPSx_hw, True); AddVx; AddWx; AddIb; end;
|
||
end;
|
||
end;
|
||
$71: begin
|
||
DoGroup12
|
||
end;
|
||
$72: begin
|
||
DoGroup13
|
||
end;
|
||
$73: begin
|
||
DoGroup14
|
||
end;
|
||
$74: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPpcmpeq, OPSx_b ); AddPq; AddQq; end;
|
||
so66: begin SetOpcode(OPpcmpeq, OPSx_b, True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$75: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPpcmpeq, OPSx_w ); AddPq; AddQq; end;
|
||
so66: begin SetOpcode(OPpcmpeq, OPSx_w, True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$76: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPpcmpeq, OPSx_d ); AddPq; AddQq; end;
|
||
so66: begin SetOpcode(OPpcmpeq, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$77: begin
|
||
DecodeSIMD([soNone]);
|
||
if SimdOpcode = soNone
|
||
then begin
|
||
if flagVex in Flags
|
||
then begin
|
||
Exclude(Flags,flagModRM);
|
||
if Vex.VectorLength = os128
|
||
then SetOpcode(OPvzeroupper)
|
||
else SetOpcode(OPvzeroall);
|
||
end
|
||
else SetOpcode(OPemms);
|
||
end;
|
||
end;
|
||
$78: begin
|
||
DecodeSIMD([soNone, so66, soF2]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPvmread); AddEy; AddGy; end;
|
||
so66: begin
|
||
DecodeModRM;
|
||
if ModRM.Index = 0
|
||
then begin SetOpcode(OPextrq); AddUdq; AddIb; AddIb; end;
|
||
end;
|
||
soF2: begin SetOpcode(OPinsert, OPSx_q); AddVq; AddUdq; AddIb; AddIb; end;
|
||
end;
|
||
end;
|
||
$79: begin
|
||
DecodeSIMD([soNone, so66, soF2]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPvmwrite); AddGy; AddEy; end;
|
||
so66: begin SetOpcode(OPextrq); AddVq; AddUdq; end;
|
||
soF2: begin SetOpcode(OPinsert, OPSx_q); AddVq; AddUdq; end;
|
||
end;
|
||
end;
|
||
// $7A..$7B: OPX_Invalid
|
||
$7C: begin
|
||
DecodeSIMD([so66, soF2]);
|
||
case SimdOpcode of
|
||
so66: begin SetOpcode(OPhadd, OPSx_pd, True); AddVpd; AddHpd; AddWpd; end;
|
||
soF2: begin SetOpcode(OPhadd, OPSx_ps, True); AddVps; AddHps; AddWps; end;
|
||
end;
|
||
end;
|
||
$7D: begin
|
||
DecodeSIMD([so66, soF2]);
|
||
case SimdOpcode of
|
||
so66: begin SetOpcode(OPsub, OPSx_pd, True); AddVpd; AddHpd; AddWpd; end;
|
||
soF2: begin SetOpcode(OPsub, OPSx_ps, True); AddVps; AddHps; AddWps; end;
|
||
end;
|
||
end;
|
||
$7E: begin
|
||
DecodeSIMD([soNone, so66, soF3]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmov, OPS_d_q ); AddEy; AddPy; end;
|
||
so66: begin SetOpcode(OPmov, OPS_d_q, True); AddEy; AddVy; end;
|
||
soF3: begin SetOpcode(OPmov, OPSx_q , True); AddVq; AddWq; end;
|
||
end;
|
||
end;
|
||
$7F: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmov, OPSx_q ); AddQq; AddPq; end;
|
||
so66: begin SetOpcode(OPmov, OPS_Wxx(OPSx_dqa, OPSx_dqa32, OPSx_dqa64), True); AddWx; AddVx; end;
|
||
soF2: begin SetOpcode(OPmov, OPS_Wxx(OPSx_dqu, OPSx_dqu8, OPSx_dqu16), True); AddWx; AddVx; end;
|
||
soF3: begin SetOpcode(OPmov, OPS_Wxx(OPSx_dqu, OPSx_dqu32, OPSx_dqu64), True); AddWx; AddVx; 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);
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_FS);
|
||
end;
|
||
$A1: begin
|
||
Default64;
|
||
SetOpcode(OPpop);
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_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;
|
||
AddReg(regGeneral, os8, REG_C);
|
||
end;
|
||
// $A6..$A7: OPX_Invalid
|
||
$A8: begin
|
||
Default64;
|
||
SetOpcode(OPpush);
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_GS);
|
||
end;
|
||
$A9: begin
|
||
Default64;
|
||
SetOpcode(OPpop);
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_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;
|
||
AddReg(regGeneral, os8, REG_C);
|
||
end;
|
||
$AE: begin
|
||
DoGroup15;
|
||
end;
|
||
$AF: begin
|
||
SetOpcode(OPimul);
|
||
AddGv; AddEv;
|
||
end;
|
||
//---
|
||
$B0: begin
|
||
SetOpcode(OPcmpxchg);
|
||
AddEb; AddGb;
|
||
CheckLock;
|
||
end;
|
||
$B1: begin
|
||
SetOpcode(OPcmpxchg);
|
||
AddEv; AddGv;
|
||
CheckLock;
|
||
end;
|
||
$B2: begin
|
||
SetOpcode(OPlss);
|
||
AddGv; AddMp;
|
||
end;
|
||
$B3: begin
|
||
SetOpcode(OPbtr);
|
||
AddEv; AddGv;
|
||
end;
|
||
$B4: begin
|
||
SetOpcode(OPlfs);
|
||
AddGv; AddMp;
|
||
end;
|
||
$B5: begin
|
||
SetOpcode(OPlgs);
|
||
AddGv; AddMp;
|
||
end;
|
||
$B6: begin
|
||
SetOpcode(OPmovzx);
|
||
AddGv; AddEb;
|
||
end;
|
||
$B7: begin
|
||
SetOpcode(Opmovzx);
|
||
AddGv; AddEw;
|
||
end;
|
||
$B8: begin
|
||
DecodeSIMD([soNone, soF3], True);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPjmpe ); AddIz; end; // Itanium SDM, volume 4, page 256.
|
||
soF3: begin SetOpcode(OPpopcnt); AddGv; AddEv; end;
|
||
end;
|
||
end;
|
||
$B9: begin
|
||
DoGroup10;
|
||
end;
|
||
$BA: begin
|
||
DoGroup8;
|
||
end;
|
||
$BB: begin
|
||
SetOpcode(OPbtc);
|
||
AddEv; AddGv;
|
||
end;
|
||
$BC: begin
|
||
DecodeSIMD([soNone, soF3], True);
|
||
case SimdOpcode of
|
||
soNone,
|
||
so66: begin SetOpcode(OPbsf ); AddGv; AddEv; end;
|
||
soF3: begin SetOpcode(OPtzcnt); AddGv; AddEv; end;
|
||
end;
|
||
end;
|
||
$BD: begin
|
||
DecodeSIMD([soNone, soF3], True);
|
||
case SimdOpcode of
|
||
soNone,
|
||
so66: begin SetOpcode(OPbsr ); AddGv; AddEv; end;
|
||
soF3: begin SetOpcode(OPlzcnt); AddGv; AddEv; end;
|
||
end;
|
||
end;
|
||
$BE: begin
|
||
SetOpcode(OPmovsx);
|
||
AddGv; AddEb;
|
||
end;
|
||
$BF: begin
|
||
SetOpcode(OPmovsx);
|
||
AddGv; AddEw;
|
||
end;
|
||
//---
|
||
$C0: begin
|
||
DecodeSIMD([soNone]);
|
||
if SimdOpcode = soNone
|
||
then begin SetOpcode(OPxadd); AddEb; AddGb; CheckLock; end;
|
||
end;
|
||
$C1: begin
|
||
DecodeSIMD([soNone]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPxadd); AddEv; AddGv; CheckLock; end;
|
||
so66: begin SetOpcode(OPxadd); AddEw; AddGw; CheckLock; end;
|
||
end;
|
||
end;
|
||
$C2: begin
|
||
DecodeSIMD;
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPcmp, OPSx_ps, True); AddVps; AddHps; AddWps; AddIb end;
|
||
so66: begin SetOpcode(OPcmp, OPSx_pd, True); AddVpd; AddHpd; AddWpd; AddIb end;
|
||
soF2: begin SetOpcode(OPcmp, OPSx_sd, True); AddVsd; AddHsd; AddWsd; AddIb end;
|
||
soF3: begin SetOpcode(OPcmp, OPSx_ss, True); AddVss; AddHss; AddWss; AddIb end;
|
||
end;
|
||
end;
|
||
$C3: begin
|
||
DecodeSIMD([soNone]);
|
||
if SimdOpcode = soNone
|
||
then begin
|
||
SetOpcode(OPmovnt, OPSx_i);
|
||
AddMy; AddGy;
|
||
end;
|
||
end;
|
||
$C4: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPpinsr, OPSx_w ); AddPq; AddRy_Mw; AddIb end;
|
||
so66: begin SetOpcode(OPpinsr, OPSx_w, True); AddVdq; AddHx; AddRy_Mw; AddIb end;
|
||
end;
|
||
end;
|
||
$C5: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPpextr, OPSx_w ); AddGd; AddNq; AddIb end;
|
||
so66: begin SetOpcode(OPpextr, OPSx_w, True); AddGd; AddUdq; AddIb end;
|
||
end;
|
||
end;
|
||
$C6: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPshuf, OPSx_ps, True); AddVps; AddHps; AddWps; AddIb end;
|
||
so66: begin SetOpcode(OPshuf, OPSx_pd, True); AddVpd; AddHpd; AddWpd; AddIb end;
|
||
end;
|
||
end;
|
||
$C7: begin
|
||
DoGroup9;
|
||
end;
|
||
$C8..$CF: begin
|
||
SetOpcode(OPbswap);
|
||
AddOpcReg(regGeneral, OperandSize, Code[CodeIdx] and $07);
|
||
end;
|
||
//---
|
||
$D0: begin
|
||
DecodeSIMD([so66, soF2]);
|
||
case SimdOpcode of
|
||
so66: begin SetOpcode(OPaddsub, OPSx_pd, True); AddVpd; AddHpd; AddWpd; end;
|
||
soF2: begin SetOpcode(OPaddsub, OPSx_ps, True); AddVps; AddHps; AddWps; end;
|
||
end;
|
||
end;
|
||
$D1..$D5, $D8..$DF: begin
|
||
idx := Code[CodeIdx] and $F;
|
||
DecodeSIMD([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], True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$D6: begin
|
||
DecodeSIMD([so66, soF2, soF3]);
|
||
case SimdOpcode of
|
||
so66: begin SetOpcode(OPmov, OPSx_q, True); AddWq; AddVq; end;
|
||
soF2: begin SetOpcode(OPmovdq2q ); AddPq; AddUq; end;
|
||
soF3: begin SetOpcode(OPmovq2dq ); AddVdq; AddNq; end;
|
||
end;
|
||
end;
|
||
$D7: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPpmovmskb ); AddGd; AddNq; end;
|
||
so66: begin SetOpcode(OPpmovmskb, OPSnone, True); AddGd; AddUx; end;
|
||
end;
|
||
end;
|
||
// $D8..$DF: see $D1
|
||
//---
|
||
$E0..$E5, $E8..$EF: begin
|
||
idx := Code[CodeIdx] and $F;
|
||
DecodeSIMD([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], True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$E6: begin
|
||
DecodeSIMD([so66, soF2, soF3]);
|
||
case SimdOpcode of
|
||
so66: begin SetOpcode(OPcvttpd2, OPSx_dq, True); AddVx; AddWpd; end;
|
||
soF2: begin SetOpcode(OPcvtpd2, OPSx_dq, True); AddVx; AddWpd; end;
|
||
soF3: begin SetOpcode(OPcvtdq2, OPSx_pd, True); AddVx; AddWpd; end;
|
||
end;
|
||
end;
|
||
$E7: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmovnt, OPSx_q ); AddMq; AddPq; end;
|
||
so66: begin SetOpcode(OPmovnt, OPSx_dq, True); AddMx; AddVx; end;
|
||
end;
|
||
end;
|
||
// $E8..$EF: see $E0
|
||
$F0: begin
|
||
DecodeSIMD([soF2]);
|
||
if SimdOpcode = soF2
|
||
then begin SetOpcode(OPlddqu, OPSnone, True); AddVx; AddMx; end;
|
||
end;
|
||
$F1..$F6, $F8..$FE: begin
|
||
idx := Code[CodeIdx] and $F;
|
||
DecodeSIMD([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], True); AddVx; AddHx; AddWx; end;
|
||
end;
|
||
end;
|
||
$F7: begin
|
||
DecodeSIMD([soNone, so66]);
|
||
case SimdOpcode of
|
||
soNone: begin SetOpcode(OPmaskmov, OPSx_q ); AddPq; AddNq; end;
|
||
so66: begin SetOpcode(OPmaskmov, OPSx_dqu, True); AddVdq; AddUdq; end;
|
||
end;
|
||
end;
|
||
// $F8..$FE: see $F1
|
||
$FF: SetOpcode(OPud1);
|
||
end;
|
||
|
||
if not HasOpcode
|
||
then SetOpcode(OPX_Invalid);
|
||
end;
|
||
|
||
procedure TX86Disassembler.Do3ByteOpcode38;
|
||
begin
|
||
if Code[CodeIdx] = $F3
|
||
then begin
|
||
DoGroup17;
|
||
Exit;
|
||
end;
|
||
|
||
DecodeSIMD([], Code[CodeIdx] in [$F0, $F1]);
|
||
case SimdOpcode of
|
||
soNone: begin
|
||
case Code[CodeIdx] of
|
||
$00: begin SetOpcode(OPpshuf, OPSx_b ); AddPq; AddQq; end;
|
||
$01: begin SetOpcode(OPphadd, OPSx_w ); AddPq; AddQq; end;
|
||
$02: begin SetOpcode(OPphadd, OPSx_d ); AddPq; AddQq; end;
|
||
$03: begin SetOpcode(OPphaddsw ); AddPq; AddQq; end;
|
||
$04: begin SetOpcode(OPpmaddubsw ); AddPq; AddQq; end;
|
||
$05: begin SetOpcode(OPphsub, OPSx_w ); AddPq; AddQq; end;
|
||
$06: begin SetOpcode(OPphsub, OPSx_d ); AddPq; AddQq; end;
|
||
$07: begin SetOpcode(OPphsubsw ); AddPq; AddQq; end;
|
||
$08: begin SetOpcode(OPpsign, OPSx_b ); AddPq; AddQq; end;
|
||
$09: begin SetOpcode(OPpsign, OPSx_w ); AddPq; AddQq; end;
|
||
$0A: begin SetOpcode(OPpsign, OPSx_d ); AddPq; AddQq; end;
|
||
$0B: begin SetOpcode(OPpmulhrsw ); AddPq; AddQq; end;
|
||
$1C: begin SetOpcode(OPpabs, OPSx_b ); AddPq; AddQq; end;
|
||
$1D: begin SetOpcode(OPpabs, OPSx_w ); AddPq; AddQq; end;
|
||
$1E: begin SetOpcode(OPpabs, OPSx_d ); AddPq; AddQq; end;
|
||
$C8: begin SetOpcode(OPsha1nexte ); AddVdq; AddWdq; end;
|
||
$C9: begin SetOpcode(OPsha1msg1 ); AddVdq; AddWdq; end;
|
||
$CA: begin SetOpcode(OPsha1msg2 ); AddVdq; AddWdq; end;
|
||
$CB: begin SetOpcode(OPsha256rnds2 ); AddVdq; AddWdq; end;
|
||
$CC: begin SetOpcode(OPsha256msg1 ); AddVdq; AddWdq; end;
|
||
$CD: begin SetOpcode(OPsha256msg2 ); AddVdq; AddWdq; end;
|
||
$F0: begin SetOpcode(OPmov, OPSc_be ); AddGy; AddMy; end;
|
||
$F1: begin SetOpcode(OPmov, OPSc_be ); AddMy; AddGy; end;
|
||
$F2: begin SetOpcode(OPandn ); AddGy; AddBy; AddEy; CheckVex; end;
|
||
$F5: begin SetOpcode(OPbzhi ); AddGy; AddEy; AddBy; CheckVex; end;
|
||
$F7: begin SetOpcode(OPbextr ); AddGy; AddEy; AddBy; CheckVex; end;
|
||
end;
|
||
end;
|
||
so66: begin
|
||
case Code[CodeIdx] of
|
||
$00: begin SetOpcode(OPpshuf, OPSx_b, True); AddVx; AddHx; AddWx; end;
|
||
$01: begin SetOpcode(OPphadd, OPSx_w, True); AddVx; AddHx; AddWx; end;
|
||
$02: begin SetOpcode(OPphadd, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
$03: begin SetOpcode(OPphaddsw, OPSnone, True); AddVx; AddHx; AddWx; end;
|
||
$04: begin SetOpcode(OPpmaddubsw, OPSnone, True); AddVx; AddHx; AddWx; end;
|
||
$05: begin SetOpcode(OPphsub, OPSx_w, True); AddVx; AddHx; AddWx; end;
|
||
$06: begin SetOpcode(OPphsub, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
$07: begin SetOpcode(OPphsubsw, OPSnone, True); AddVx; AddHx; AddWx; end;
|
||
$08: begin SetOpcode(OPpsign, OPSx_b, True); AddVx; AddHx; AddWx; end;
|
||
$09: begin SetOpcode(OPpsign, OPSx_w, True); AddVx; AddHx; AddWx; end;
|
||
$0A: begin SetOpcode(OPpsign, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
$0B: begin SetOpcode(OPpmulhrsw, OPSnone, True); AddVx; AddHx; AddWx; end;
|
||
$0C: begin SetOpcode(OPvpermil, OPSx_ps ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$0D: begin SetOpcode(OPvpermil, OPSx_pd ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$0E: begin SetOpcode(OPvtest, OPSx_ps ); AddVx; AddWx; CheckVex; end;
|
||
$0F: begin SetOpcode(OPvtest, OPSx_pd ); AddVx; AddWx; CheckVex; end;
|
||
$10: begin SetOpcode(OPpblendvb ); AddVdq; AddWdq; end;
|
||
$13: begin SetOpcode(OPvcvtph2ps ); AddVx; AddUx_Mq; CheckVex; end;
|
||
$14: begin SetOpcode(OPblendv, OPSx_ps ); AddVdq; AddWdq; AddReg(regXmm, os128, 0); end;
|
||
$15: begin SetOpcode(OPblendv, OPSx_pd ); AddVdq; AddWdq; AddReg(regXmm, os128, 0); end;
|
||
$16: begin SetOpcode(OPvperm, OPSx_ps ); AddVqq; AddHqq; AddWqq; CheckVex; end;
|
||
$17: begin SetOpcode(OPptest, OPSnone, True); AddVx; AddWx; end;
|
||
$18: begin SetOpcode(OPvbroadcast, OPSx_ss ); AddVx; AddWd; CheckVex; end;
|
||
$19: begin SetOpcode(OPvbroadcast, OPSx_sd ); AddVqq; AddWq; CheckVex; end;
|
||
$1A: begin SetOpcode(OPvbroadcast, OPSx_f128 ); AddVqq; AddMdq; CheckVex; end;
|
||
$1C: begin SetOpcode(OPpabs, OPSx_b, True); AddVx; AddWx; end;
|
||
$1D: begin SetOpcode(OPpabs, OPSx_w, True); AddVx; AddWx; end;
|
||
$1E: begin SetOpcode(OPpabs, OPSx_d, True); AddVx; AddWx; end;
|
||
$20: begin SetOpcode(OPpmovsx, OPSv_bw, True); AddVx; AddUx_Mq; end;
|
||
$21: begin SetOpcode(OPpmovsx, OPSv_bd, True); AddVx; AddUx_Md; end;
|
||
$22: begin SetOpcode(OPpmovsx, OPSv_bq, True); AddVx; AddUx_Mw; end;
|
||
$23: begin SetOpcode(OPpmovsx, OPSv_wd, True); AddVx; AddUx_Mq; end;
|
||
$24: begin SetOpcode(OPpmovsx, OPSv_wq, True); AddVx; AddUx_Md; end;
|
||
$25: begin SetOpcode(OPpmovsx, OPSv_dq, True); AddVx; AddUx_Mq; end;
|
||
$28: begin SetOpcode(OPpmuldq, OPSnone, True); AddVx; AddHx; AddWx; end;
|
||
$29: begin SetOpcode(OPpcmpeq, OPSx_q, True); AddVx; AddHx; AddWx; end;
|
||
$2A: begin SetOpcode(OPmovnt, OPSx_dqa, True); AddVx; AddMx; end;
|
||
$2B: begin SetOpcode(OPpackusdw, OPSnone, True); AddVx; AddHx; AddWx; end;
|
||
$2C: begin SetOpcode(OPmaskmov, OPSx_ps, True); AddVx; AddHx; AddMx; CheckVex; end;
|
||
$2D: begin SetOpcode(OPmaskmov, OPSx_pd, True); AddVx; AddHx; AddMx; CheckVex; end;
|
||
$2E: begin SetOpcode(OPmaskmov, OPSx_ps, True); AddMx; AddHx; AddVx; CheckVex; end;
|
||
$2F: begin SetOpcode(OPmaskmov, OPSx_pd, True); AddMx; AddHx; AddVx; CheckVex; end;
|
||
$30: begin SetOpcode(OPpmovzx, OPSv_bw, True); AddVx; AddUx_Mq; end;
|
||
$31: begin SetOpcode(OPpmovzx, OPSv_bd, True); AddVx; AddUx_Md; end;
|
||
$32: begin SetOpcode(OPpmovzx, OPSv_bq, True); AddVx; AddUx_Mw; end;
|
||
$33: begin SetOpcode(OPpmovzx, OPSv_wd, True); AddVx; AddUx_Mq; end;
|
||
$34: begin SetOpcode(OPpmovzx, OPSv_wq, True); AddVx; AddUx_Md; end;
|
||
$35: begin SetOpcode(OPpmovzx, OPSv_dq, True); AddVx; AddUx_Mq; end;
|
||
$36: begin SetOpcode(OPvperm, OPSx_d ); AddVqq; AddHqq; AddWqq; CheckVex; end;
|
||
$37: begin SetOpcode(OPpcmpgt, OPSx_q, True); AddVx; AddHx; AddWx; end;
|
||
$38: begin SetOpcode(OPpmins, OPSx_b, True); AddVx; AddHx; AddWx; end;
|
||
$39: begin SetOpcode(OPpmins, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
$3A: begin SetOpcode(OPpminu, OPSx_w, True); AddVx; AddHx; AddWx; end;
|
||
$3B: begin SetOpcode(OPpminu, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
$3C: begin SetOpcode(OPpmaxs, OPSx_b, True); AddVx; AddHx; AddWx; end;
|
||
$3D: begin SetOpcode(OPpmaxs, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
$3E: begin SetOpcode(OPpmaxu, OPSx_w, True); AddVx; AddHx; AddWx; end;
|
||
$3F: begin SetOpcode(OPpmaxu, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
$40: begin SetOpcode(OPpmull, OPSx_d, True); AddVx; AddHx; AddWx; end;
|
||
$41: begin SetOpcode(OPphminposuw, OPSnone, True); AddVdq; AddWdq; end;
|
||
$45: begin SetOpcode(OPvpsrlv, OPS_d_q ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$46: begin SetOpcode(OPvpsrav, OPSx_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$47: begin SetOpcode(OPvpsllv, OPS_d_q ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$58: begin SetOpcode(OPvpbroadcast, OPSx_d ); AddVx; AddWx; CheckVex; end;
|
||
$59: begin SetOpcode(OPvpbroadcast, OPSx_q ); AddVx; AddWx; CheckVex; end;
|
||
$5A: begin SetOpcode(OPvpbroadcast, OPSx_i128 ); AddVqq; AddMdq; CheckVex; end;
|
||
$78: begin SetOpcode(OPvpbroadcast, OPSx_b ); AddVx; AddWx; CheckVex; end;
|
||
$79: begin SetOpcode(OPvpbroadcast, OPSx_w ); AddVx; AddWx; CheckVex; end;
|
||
$80: begin SetOpcode(OPinvept ); AddGy; AddMdq; end;
|
||
$81: begin SetOpcode(OPinvvpid ); AddGy; AddMdq; end;
|
||
$82: begin SetOpcode(OPinvpcid ); AddGy; AddMdq; end;
|
||
$8C: begin SetOpcode(OPvpmaskmov, OPS_d_q ); AddVx; AddHx; AddMx; CheckVex; end;
|
||
$8E: begin SetOpcode(OPvpmaskmov, OPS_d_q ); AddMx; AddHx; AddVx; CheckVex; end;
|
||
$90: begin SetOpcode(OPvgatherd, OPS_d_q ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$91: begin SetOpcode(OPvgatherq, OPS_d_q ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$92: begin SetOpcode(OPvgatherd, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$93: begin SetOpcode(OPvgatherq, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$96: begin SetOpcode(OPvfmaddsub132,OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$97: begin SetOpcode(OPvfmsubadd132,OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$98: begin SetOpcode(OPvfmadd132, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$99: begin SetOpcode(OPvfmadd132, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$9A: begin SetOpcode(OPvfmsub132, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$9B: begin SetOpcode(OPvfmsub132, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$9C: begin SetOpcode(OPvfnmadd132, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$9D: begin SetOpcode(OPvfnmadd132, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$9E: begin SetOpcode(OPvfnmsub132, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$9F: begin SetOpcode(OPvfnmsub132, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$A6: begin SetOpcode(OPvfmaddsub213,OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$A7: begin SetOpcode(OPvfmsubadd213,OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$A8: begin SetOpcode(OPvfmadd213, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$A9: begin SetOpcode(OPvfmadd213, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$AA: begin SetOpcode(OPvfmsub213, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$AB: begin SetOpcode(OPvfmsub213, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$AC: begin SetOpcode(OPvfnmadd213, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$AD: begin SetOpcode(OPvfnmadd213, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$AE: begin SetOpcode(OPvfnmsub213, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$AF: begin SetOpcode(OPvfnmsub213, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$B6: begin SetOpcode(OPvfmaddsub231,OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$B7: begin SetOpcode(OPvfmsubadd231,OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$B8: begin SetOpcode(OPvfmadd231, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$B9: begin SetOpcode(OPvfmadd231, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$BA: begin SetOpcode(OPvfmsub231, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$BB: begin SetOpcode(OPvfmsub231, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$BC: begin SetOpcode(OPvfnmadd231, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$BD: begin SetOpcode(OPvfnmadd231, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$BE: begin SetOpcode(OPvfnmsub231, OPS_ps_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$BF: begin SetOpcode(OPvfnmsub231, OPS_ss_d ); AddVx; AddHx; AddWx; CheckVex; end;
|
||
$DB: begin SetOpcode(OPaesimc, OPSnone, True); AddVdq; AddWdq; end;
|
||
$DC: begin SetOpcode(OPaesenc, OPSnone, True); AddVdq; AddHx; AddWdq; end;
|
||
$DD: begin SetOpcode(OPaesenclast, OPSnone, True); AddVdq; AddHx; AddWdq; end;
|
||
$DE: begin SetOpcode(OPaesdec, OPSnone, True); AddVdq; AddHx; AddWdq; end;
|
||
$DF: begin SetOpcode(OPaesdeclast, OPSnone, True); AddVdq; AddHx; AddWdq; end;
|
||
$F0: begin SetOpcode(OPmov, OPSc_be ); AddGw; AddMw; end;
|
||
$F1: begin SetOpcode(OPmov, OPSc_be ); AddMw; AddGw; end;
|
||
$F6: begin SetOpcode(OPadcx ); AddGy; AddEy; end;
|
||
$F7: begin SetOpcode(OPshl, OPSx_x ); AddGy; AddEy; AddBy; CheckVex; end;
|
||
end;
|
||
end;
|
||
soF2: begin
|
||
case Code[CodeIdx] of
|
||
$F0: begin SetOpcode(OPcrc32 ); AddGd; AddEb; end;
|
||
$F1: begin
|
||
SetOpcode(OPcrc32);
|
||
AddGd;
|
||
if pre66 in Flags then AddEw else AddEy;
|
||
Flags := Flags - [pre66];
|
||
end;
|
||
$F5: begin SetOpcode(OPpdep ); AddGy; AddBy; AddEy; CheckVex; end;
|
||
$F6: begin SetOpcode(OPmul, OPSx_x ); AddBy; AddGy; AddReg(regGeneral, MODE_SIZE[ProcessMode], REG_D); AddEy; CheckVex; end;
|
||
$F7: begin SetOpcode(OPshr, OPSx_x ); AddGy; AddEy; AddBy; CheckVex; end;
|
||
end;
|
||
end;
|
||
soF3: begin
|
||
case Code[CodeIdx] of
|
||
$F5: begin SetOpcode(OPpext ); AddGy; AddBy; AddEy; CheckVex; end;
|
||
$F6: begin SetOpcode(OPadox ); AddGy; AddEy; end;
|
||
$F7: begin SetOpcode(OPsar, OPSx_x ); AddGy; AddEy; AddBy; CheckVex; end;
|
||
end;
|
||
end;
|
||
end;
|
||
if HasOpcode
|
||
then ClearSIMDPrefix;
|
||
end;
|
||
|
||
procedure TX86Disassembler.Do3ByteOpcode3A;
|
||
begin
|
||
DecodeSIMD([], Code[CodeIdx] in [$F0, $F1]);
|
||
case SimdOpcode of
|
||
soNone: begin
|
||
case Code[CodeIdx] of
|
||
$0F: begin SetOpcode(OPpalignr, OPSnone ); AddPq; AddQq; AddIb; end;
|
||
$CC: begin SetOpcode(OPsha1rnds4, OPSnone ); AddVdq; AddWdq; AddIb; end;
|
||
end;
|
||
end;
|
||
so66: begin
|
||
case Code[CodeIdx] of
|
||
$00: begin SetOpcode(OPvperm, OPSx_q ); AddVqq; AddWqq; AddIb; CheckVex; end;
|
||
$01: begin SetOpcode(OPvperm, OPSx_pd ); AddVqq; AddWqq; AddIb; CheckVex; end;
|
||
$02: begin SetOpcode(OPpblend, OPSx_d, True); AddVx; AddHx; AddWx; AddIb; CheckVex; end;
|
||
$03: begin SetOpcode(OPvalign, OPS_d_q ); AddVqq; AddWqq; AddIb; CheckVex; end;
|
||
$04: begin SetOpcode(OPvpermil, OPSx_ps ); AddVx; AddWx; AddIb; CheckVex; end;
|
||
$05: begin SetOpcode(OPvpermil, OPSx_pd ); AddVx; AddWx; AddIb; CheckVex; end;
|
||
$06: begin SetOpcode(OPvperm2, OPSx_f128 ); AddVqq; AddHqq; AddWqq; AddIb; CheckVex; end;
|
||
$08: begin SetOpcode(OPround, OPSx_ps, True); AddVx; AddWx; AddIb; end;
|
||
$09: begin SetOpcode(OPround, OPSx_pd, True); AddVx; AddWx; AddIb; end;
|
||
$0A: begin SetOpcode(OPround, OPSx_ss, True); AddVss; AddHx; AddWss; AddIb; end;
|
||
$0B: begin SetOpcode(OPround, OPSx_sd, True); AddVsd; AddHx; AddWsd; AddIb; end;
|
||
$0C: begin SetOpcode(OPblend, OPSx_ps, True); AddVx; AddHx; AddWx; AddIb; end;
|
||
$0D: begin SetOpcode(OPblend, OPSx_pd, True); AddVx; AddHx; AddWx; AddIb; end;
|
||
$0E: begin SetOpcode(OPpblend, OPSx_w, True); AddVx; AddHx; AddWx; AddIb; end;
|
||
$0F: begin SetOpcode(OPpalignr, OPSnone, True); AddVx; AddHx; AddWx; AddIb; end;
|
||
$14: begin SetOpcode(OPpextr, OPSx_b, True); AddRd_Mb; AddVq; AddIb; end;
|
||
$15: begin SetOpcode(OPpextr, OPSx_w, True); AddRd_Mw; AddVq; AddIb; end;
|
||
$16: begin SetOpcode(OPpextr, OPS_d_q, True); AddEy; AddVq; AddIb; end;
|
||
$17: begin SetOpcode(OPextract, OPSx_ps, True); AddEd; AddVdq; AddIb; end;
|
||
$18: begin SetOpcode(OPinsert, OPSx_f128,True); AddVqq; AddHqq; AddWqq; AddIb; CheckVex; end;
|
||
$19: begin SetOpcode(OPextract, OPSx_f128,True); AddWdq; AddVqq; AddIb; CheckVex; end;
|
||
$1D: begin SetOpcode(OPcvtps2, OPSx_ph, True); AddWx_Mq; AddVx; AddIb; CheckVex; end;
|
||
$20: begin SetOpcode(OPpinsr, OPSx_b, True); AddVdq; AddHx; AddRd_Mb; AddIb; end;
|
||
$21: begin SetOpcode(OPinsert, OPSx_ps, True); AddVdq; AddHx; AddUdq_Md; AddIb; end;
|
||
$22: begin SetOpcode(OPpinsr, OPS_d_q, True); AddVdq; AddHx; AddEy; AddIb; end;
|
||
$38: begin SetOpcode(OPinsert, OPSx_i128,True); AddVqq; AddHqq; AddWqq; AddIb; CheckVex; end;
|
||
$39: begin SetOpcode(OPextract, OPSx_i128,True); AddWdq; AddVqq; AddIb; CheckVex; end;
|
||
$40: begin SetOpcode(OPdp, OPSx_ps, True); AddVx; AddHx; AddWx; AddIb; end;
|
||
$41: begin SetOpcode(OPdp, OPSx_pd, True); AddVdq; AddHx; AddWdq; AddIb; end;
|
||
$42: begin SetOpcode(OPmpsadbw, OPSnone, True); AddVx; AddHx; AddWx; AddIb; end;
|
||
$44: begin SetOpcode(OPpclmulqdq, OPSnone, True); AddVdq; AddHx; AddWdq; AddIb; end;
|
||
$46: begin SetOpcode(OPvperm2, OPSx_i128 ); AddVqq; AddHqq; AddWqq; AddIb; CheckVex; end;
|
||
$4A: begin SetOpcode(OPblendv, OPSx_ps, True); AddVx; AddHx; AddWx; AddLx; CheckVex; end;
|
||
$4B: begin SetOpcode(OPblendv, OPSx_pd, True); AddVx; AddHx; AddWx; AddLx; CheckVex; end;
|
||
$4C: begin SetOpcode(OPpblendvb, OPSnone, True); AddVx; AddHx; AddWx; AddLx; CheckVex; end;
|
||
$60: begin SetOpcode(OPpcmpestrm, OPSnone, True); AddVdq; AddWdq; AddIb; end;
|
||
$61: begin SetOpcode(OPpcmpestri, OPSnone, True); AddVdq; AddWdq; AddIb; end;
|
||
$62: begin SetOpcode(OPpcmpistrm, OPSnone, True); AddVdq; AddWdq; AddIb; end;
|
||
$63: begin SetOpcode(OPpcmpistri, OPSnone, True); AddVdq; AddWdq; AddIb; end;
|
||
$DF: begin SetOpcode(OPaeskeygenassist,OPSnone,True);AddVdq; AddWdq; AddIb; end;
|
||
end;
|
||
end;
|
||
soF2: begin
|
||
case Code[CodeIdx] of
|
||
$F0: begin SetOpcode(OProrx ); AddGy; AddEy; AddIb; CheckVex; end;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoVex(ASize: Byte);
|
||
const
|
||
SIMDMAP: array[0..3] of TSimdOpcode = (soNone, so66, soF3, soF2);
|
||
LENMAP: array[0..3] of TOperandSize = (os128, os256, os512, os0);
|
||
var
|
||
idx, mm: Byte;
|
||
begin
|
||
Assert(ASize in [2..4], Format('Invalid VEX size: %u', [ASize]));
|
||
|
||
// remove rexRXBW flags, they are illegal. the presence of flagRex wil signal this
|
||
Flags := Flags - [rexR, rexX, rexB, rexW];
|
||
|
||
idx := CodeIdx + 1;
|
||
case ASize of
|
||
2: begin
|
||
// VEX 2
|
||
// Rvvv vLpp
|
||
if Code[idx] and $80 = 0 then Include(Flags, rexR);
|
||
Vex.Index := ((Code[idx] shr 3) and $0F) xor $0F;
|
||
Vex.VectorLength := LENMAP[(Code[idx] shr 2) and $01];
|
||
SimdOpcode := SIMDMAP[Code[idx] and $03];
|
||
mm := 1;
|
||
end;
|
||
3: begin
|
||
// VEX 3
|
||
// RXBm mmmm | Wvvv vLpp
|
||
if Code[idx] and $80 = 0 then Include(Flags, rexR);
|
||
if Code[idx] and $40 = 0 then Include(Flags, rexX);
|
||
if Code[idx] and $20 = 0 then Include(Flags, rexB);
|
||
mm := Code[idx] and $1F;
|
||
|
||
Inc(idx);
|
||
if Code[idx] and $80 <> 0 then Include(Flags, rexW);
|
||
Vex.Index := ((Code[idx] shr 3) and $0F) xor $0F;
|
||
Vex.VectorLength := LENMAP[(Code[idx] shr 2) and $01];
|
||
SimdOpcode := SIMDMAP[Code[idx] and $03];
|
||
end;
|
||
4: begin
|
||
// EVEX
|
||
// RXBR' 00mm | Wvvv v1pp | zL'Lb V'aaa
|
||
// the RXB fields are mapped to the rex RXB flags
|
||
if Code[idx] and $80 = 0 then Include(Flags, rexR);
|
||
// Intel(r) 64 and IA-32 Architectures Software Developer’s Manual Volume 2:
|
||
// Table 2-30. EVEX Prefix Bit Field Functional Grouping seems to indicate
|
||
// that rexX is inverted and evexX not, but they appear to be the same
|
||
if Code[idx] and $40 = 0 then Flags := Flags + [rexX, evexX];
|
||
if Code[idx] and $20 = 0 then Include(Flags, rexB);
|
||
if Code[idx] and $10 = 0 then Include(Flags, evexR);
|
||
mm := Code[idx] and $03;
|
||
|
||
Inc(idx);
|
||
if Code[idx] and $80 <> 0 then Include(Flags, rexW);
|
||
Vex.Index := ((Code[idx] shr 3) and $0F) xor $0F;
|
||
SimdOpcode := SIMDMAP[Code[idx] and $03];
|
||
|
||
Inc(idx);
|
||
if Code[idx] and $80 <> 0 then Include(Flags, evexZ);
|
||
Vex.VectorLength := LENMAP[(Code[idx] shr 5) and $03];
|
||
if Code[idx] and $10 <> 0 then Include(Flags, evexB);
|
||
if Code[idx] and $08 = 0 then Include(Flags, evexV);
|
||
Vex.MaskIndex := Code[idx] and $07;
|
||
|
||
Include(Flags, flagEvex);
|
||
end;
|
||
else
|
||
Exit;
|
||
end;
|
||
|
||
Include(Flags, flagVex);
|
||
Inc(CodeIdx, ASize);
|
||
Inc(ModRMIdx, ASize);
|
||
|
||
case mm of
|
||
1: Do2ByteOpcode;
|
||
2: Do3ByteOpcode38;
|
||
3: Do3ByteOpcode3A;
|
||
else
|
||
SetOpcode(OPX_InvalidVex);
|
||
end;
|
||
end;
|
||
|
||
procedure TX86Disassembler.DoDisassemble;
|
||
begin
|
||
SetOpcode(OPX_InternalUnknown);
|
||
repeat
|
||
ModRMIdx := CodeIdx + 1;
|
||
case Code[CodeIdx] of
|
||
$00..$05: begin
|
||
SetOpcode(OPadd);
|
||
AddStdOperands(Code[CodeIdx]);
|
||
CheckLock;
|
||
end;
|
||
$06: begin
|
||
SetOpcode(OPpush); Check32;
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_ES);
|
||
end;
|
||
$07: begin
|
||
SetOpcode(OPpop); Check32;
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_ES);
|
||
end;
|
||
$08..$0D: begin
|
||
SetOpcode(OPor);
|
||
AddStdOperands(Code[CodeIdx]);
|
||
CheckLock;
|
||
end;
|
||
$0E: begin
|
||
SetOpcode(OPpush); Check32;
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_CS);
|
||
end;
|
||
$0F: begin
|
||
Inc(CodeIdx);
|
||
Inc(ModRMIdx);
|
||
Do2ByteOpcode;
|
||
end;
|
||
//---
|
||
$10..$15: begin
|
||
SetOpcode(OPadc);
|
||
AddStdOperands(Code[CodeIdx]);
|
||
CheckLock;
|
||
end;
|
||
$16: begin
|
||
SetOpcode(OPpush); Check32;
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_SS);
|
||
end;
|
||
$17: begin
|
||
SetOpcode(OPpop); Check32;
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_SS);
|
||
end;
|
||
$18..$1D: begin
|
||
SetOpcode(OPsbb);
|
||
AddStdOperands(Code[CodeIdx]);
|
||
CheckLock;
|
||
end;
|
||
$1E: begin
|
||
SetOpcode(OPpush); Check32;
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_DS);
|
||
end;
|
||
$1F: begin
|
||
SetOpcode(OPpop); Check32;
|
||
AddReg(regSegment, MODE_SIZE[ProcessMode], REG_DS);
|
||
end;
|
||
//---
|
||
$20..$25: begin
|
||
SetOpcode(OPand);
|
||
AddStdOperands(Code[CodeIdx]);
|
||
CheckLock;
|
||
end;
|
||
$26: begin
|
||
Instruction^.Segment := Instruction^.Segment + Ignore64('es:');
|
||
end;
|
||
$27: begin
|
||
SetOpcode(OPdaa); Check32;
|
||
end;
|
||
$28..$2D: begin
|
||
SetOpcode(OPsub);
|
||
AddStdOperands(Code[CodeIdx]);
|
||
CheckLock;
|
||
end;
|
||
$2E: begin
|
||
Instruction^.Segment := Instruction^.Segment + Ignore64('cs:');
|
||
end;
|
||
$2F: begin
|
||
SetOpcode(OPdas); Check32;
|
||
end;
|
||
//---
|
||
$30..$35: begin
|
||
SetOpcode(OPxor);
|
||
AddStdOperands(Code[CodeIdx]);
|
||
CheckLock;
|
||
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);
|
||
AddOpcReg(regGeneral, OperandSize, Code[CodeIdx] and $07);
|
||
CheckLock;
|
||
end;
|
||
end;
|
||
//---
|
||
$50..$57: begin
|
||
Default64;
|
||
SetOpcode(OPpush);
|
||
AddOpcReg(regGeneral, OperandSize, Code[CodeIdx] and $07);
|
||
end;
|
||
$58..$5F: begin
|
||
Default64;
|
||
SetOpcode(OPpop);
|
||
AddOpcReg(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
|
||
DecodeModRM;
|
||
if (ProcessMode = dm32) and (ModRm.Mode <> 3)
|
||
then begin
|
||
SetOpcode(OPbound);
|
||
AddGv; AddMa;
|
||
end
|
||
else begin
|
||
DoVex(4);
|
||
end;
|
||
end;
|
||
$63: begin
|
||
if ProcessMode = dm64
|
||
then begin
|
||
SetOpcode(OPmovsx, OPSx_d);
|
||
AddGv; AddEd;
|
||
end
|
||
else begin
|
||
SetOpcode(OParpl);
|
||
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;
|
||
AddReg(regGeneral, os16, REG_D);
|
||
{$endif}
|
||
end;
|
||
$6D: begin
|
||
if OperandSize = os16
|
||
then SetOpcode(OPins, OPSx_w)
|
||
else SetOpcode(OPins, OPSx_d);
|
||
CheckRepeat;
|
||
{$ifdef verbose_string_instructions}
|
||
AddYz;
|
||
AddReg(regGeneral, os16, REG_D);
|
||
{$endif}
|
||
end;
|
||
$6E: begin
|
||
SetOpcode(OPouts, OPSx_b); CheckRepeat;
|
||
{$ifdef verbose_string_instructions}
|
||
AddReg(regGeneral, os16, REG_D);
|
||
AddXb;
|
||
{$endif}
|
||
end;
|
||
$6F: begin
|
||
if OperandSize = os16
|
||
then SetOpcode(OPouts, OPSx_w)
|
||
else SetOpcode(OPouts, OPSx_d);
|
||
CheckRepeat;
|
||
{$ifdef verbose_string_instructions}
|
||
AddReg(regGeneral, os16, REG_D);
|
||
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);
|
||
AddEb; AddGb;
|
||
CheckLock;
|
||
end;
|
||
$87: begin
|
||
SetOpcode(OPxchg);
|
||
AddEv; AddGv;
|
||
CheckLock;
|
||
end;
|
||
$88..$8B: begin
|
||
SetOpcode(OPmov);
|
||
AddStdOperands(Code[CodeIdx]);
|
||
end;
|
||
$8C: begin
|
||
SetOpcode(OPmov);
|
||
AddEv; AddSw;
|
||
end;
|
||
$8D: begin
|
||
SetOpcode(OPlea);
|
||
AddGv; AddM;
|
||
end;
|
||
$8E: begin
|
||
SetOpcode(OPmov);
|
||
AddSw; AddEw;
|
||
end;
|
||
$8F: begin
|
||
DoGroup1;
|
||
end;
|
||
//---
|
||
$90: begin
|
||
if preF3 in Flags
|
||
then
|
||
begin
|
||
SetOpcode(OPpause);
|
||
Exclude(Flags, preF3);
|
||
end
|
||
else if rexB in Flags
|
||
then begin
|
||
SetOpcode(OPxchg);
|
||
AddReg(regGeneral, OperandSize, 8);
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
end
|
||
else SetOpcode(OPnop);
|
||
end;
|
||
$91..$97: begin
|
||
SetOpcode(OPxchg);
|
||
AddOpcReg(regGeneral, OperandSize, Code[CodeIdx] and $07);
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
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, REG_A);
|
||
AddOb;
|
||
end;
|
||
$A1: begin
|
||
SetOpcode(OPmov);
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
AddOv;
|
||
end;
|
||
$A2: begin
|
||
SetOpcode(OPmov);
|
||
AddOb;
|
||
AddReg(regGeneral, os8, REG_A);
|
||
end;
|
||
$A3: begin
|
||
SetOpcode(OPmov);
|
||
AddOv;
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
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}
|
||
AddXv; AddYYv;
|
||
{$endif}
|
||
end;
|
||
$A8: begin
|
||
SetOpcode(OPtest);
|
||
AddReg(regGeneral, os8, REG_A);
|
||
AddIb;
|
||
end;
|
||
$A9: begin
|
||
SetOpcode(OPtest);
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
AddIz;
|
||
end;
|
||
$AA: begin
|
||
SetOpcode(OPstos, OPSx_b); CheckRepeat;
|
||
{$ifdef verbose_string_instructions}
|
||
AddYb;
|
||
AddReg(regGeneral, os8, REG_A);
|
||
{$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, REG_A);
|
||
{$endif}
|
||
end;
|
||
$AC: begin
|
||
SetOpcode(OPlods, OPSx_b); CheckRepeat;
|
||
{$ifdef verbose_string_instructions}
|
||
AddReg(regGeneral, os8, REG_A)
|
||
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, REG_A);
|
||
AddXv;
|
||
{$endif}
|
||
end;
|
||
$AE: begin
|
||
SetOpcode(OPscas, OPSx_b); CheckRepeatX;
|
||
{$ifdef verbose_string_instructions}
|
||
AddReg(regGeneral, os8, REG_A);
|
||
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, REG_A);
|
||
AddYv;
|
||
{$endif}
|
||
end;
|
||
//---
|
||
$B0..$B7: begin
|
||
SetOpcode(OPmov);
|
||
AddOpcReg(regGeneral, os8, Code[CodeIdx] and $07);
|
||
AddIb;
|
||
end;
|
||
$B8..$BF: begin
|
||
SetOpcode(OPmov);
|
||
AddOpcReg(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);
|
||
CheckRepeat;
|
||
end;
|
||
$C4: begin
|
||
DecodeModRM;
|
||
if (ProcessMode = dm32) and (ModRm.Mode <> 3)
|
||
then begin
|
||
SetOpcode(OPles);
|
||
AddGz; AddMp;
|
||
end
|
||
else begin
|
||
DoVex(3);
|
||
end;
|
||
end;
|
||
$C5: begin
|
||
DecodeModRM;
|
||
if (ProcessMode = dm32) and (ModRm.Mode <> 3)
|
||
then begin
|
||
SetOpcode(OPlds);
|
||
AddGz; AddMp;
|
||
end
|
||
else begin
|
||
DoVex(2);
|
||
end;
|
||
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, REG_A);
|
||
AddIb;
|
||
end;
|
||
$E5: begin
|
||
SetOpcode(OPin);
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
AddIb;
|
||
end;
|
||
$E6: begin
|
||
SetOpcode(OPout);
|
||
AddIb;
|
||
AddReg(regGeneral, os8, REG_A);
|
||
end;
|
||
$E7: begin
|
||
SetOpcode(OPout);
|
||
AddIb;
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
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, REG_A);
|
||
AddReg(regGeneral, os16, REG_D);
|
||
end;
|
||
$ED: begin
|
||
SetOpcode(OPin);
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
AddReg(regGeneral, os16, REG_D);
|
||
end;
|
||
$EE: begin
|
||
SetOpcode(OPout);
|
||
AddReg(regGeneral, os16, REG_D);
|
||
AddReg(regGeneral, os8, REG_A);
|
||
end;
|
||
$EF: begin
|
||
SetOpcode(OPout);
|
||
AddReg(regGeneral, os16, REG_D);
|
||
AddReg(regGeneral, OperandSize, REG_A);
|
||
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;
|
||
Vex.MaskIndex := 0;
|
||
|
||
DoDisassemble;
|
||
|
||
Instruction^.OperCnt := OperIdx;
|
||
Instruction^.ParseFlags := Flags;
|
||
Instruction^.MaskIndex := Vex.MaskIndex;
|
||
|
||
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 }
|
||
|
||
function TX86AsmInstruction.GetCodeMem: Pointer;
|
||
begin
|
||
Result := @FCodeBin[0];
|
||
end;
|
||
|
||
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; out AnInfo: TDbgInstInfo);
|
||
const
|
||
MEMPTR: array[TOperandSize] of string = (
|
||
{ os0 } '',
|
||
{ os8 } 'byte ptr ',
|
||
{ os16 } 'word ptr ',
|
||
{ os32 } 'dword ptr ',
|
||
{ os64 } 'qword ptr ',
|
||
{ os48 } '',
|
||
{ os80 } 'tbyte ptr ',
|
||
{ os128 } 'xmmword ptr ',
|
||
{ os256 } 'ymmword ptr ',
|
||
{ os512 } 'zmmword ptr ',
|
||
{ os4096 } ''
|
||
);
|
||
{$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;
|
||
TargetAddrOffs: Int64;
|
||
HasMem: Boolean;
|
||
OpcodeName: String;
|
||
Code: PByte;
|
||
begin
|
||
AnInfo := default(TDbgInstInfo);
|
||
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
|
||
S := Instr.Segment + '[' + S + ']';
|
||
if (Instr.OperCnt = 1)
|
||
// or (Instr.Operand[n].Size <> os32)
|
||
or (Instr.Operand[1].Size <> Instr.Operand[2].Size)
|
||
then S := MEMPTR[Instr.Operand[n].Size] + S;
|
||
HasMem := True;
|
||
end;
|
||
|
||
if Soper = ''
|
||
then begin
|
||
Soper := Soper + S;
|
||
if Instr.MaskIndex > 0
|
||
then Soper := Soper + Format('{k%u}', [Instr.MaskIndex]);
|
||
if evexZ in Instr.ParseFlags
|
||
then Soper := Soper + '{z}'
|
||
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}
|
||
|
||
|
||
if (Instr.OpCode.Opcode in [OPcall, OPj__, OPjcxz, OPjecxz, OPjmp, OPjmpe, OPjrcxz]) and
|
||
(Instr.OperCnt = 1) and
|
||
(hvfSigned in Instr.Operand[1].FormatFlags) and
|
||
(Instr.Operand[1].Value = '%s') // no register
|
||
then begin
|
||
TargetAddrOffs := 1;
|
||
case Instr.Operand[1].ByteCount of
|
||
1: TargetAddrOffs := shortint(PByte(@Code[Instr.Operand[1].CodeIndex])^);
|
||
2: TargetAddrOffs := smallint(PWord(@Code[Instr.Operand[1].CodeIndex])^);
|
||
4: TargetAddrOffs := Integer(PDWord(@Code[Instr.Operand[1].CodeIndex])^);
|
||
8: TargetAddrOffs := Int64(PQWord(@Code[Instr.Operand[1].CodeIndex])^);
|
||
end;
|
||
if TargetAddrOffs <> 1 then begin
|
||
AnInfo.InstrType := itJump;
|
||
{$PUSH}{$R-}{$Q-}
|
||
AnInfo.InstrTargetOffs := Int64(TDbgPtr(AAddress) - TDbgPtr(Code)) + TargetAddrOffs;
|
||
{$POP}
|
||
end;
|
||
end
|
||
else
|
||
if (Instr.OperCnt = 2) and (ofMemory in Instr.Operand[n].Flags) and (Instr.Segment = '') and
|
||
( (Instr.Operand[2].Value = 'rip%s') or (Instr.Operand[2].Value = 'eip%s') )
|
||
then begin
|
||
TargetAddrOffs := 1;
|
||
case Instr.Operand[2].ByteCount of
|
||
1: TargetAddrOffs := shortint(PByte(@Code[Instr.Operand[2].CodeIndex])^);
|
||
2: TargetAddrOffs := smallint(PWord(@Code[Instr.Operand[2].CodeIndex])^);
|
||
4: TargetAddrOffs := Integer(PDWord(@Code[Instr.Operand[2].CodeIndex])^);
|
||
8: TargetAddrOffs := Int64(PQWord(@Code[Instr.Operand[2].CodeIndex])^);
|
||
end;
|
||
if TargetAddrOffs <> 1 then begin
|
||
AnInfo.InstrType := itAny;
|
||
{$PUSH}{$R-}{$Q-}
|
||
AnInfo.InstrTargetOffs := Int64(TDbgPtr(AAddress) - TDbgPtr(Code)) + TargetAddrOffs;
|
||
{$POP}
|
||
end;
|
||
end;
|
||
|
||
OpcodeName := OPCODE_PREFIX[Instr.OpCode.Prefix];
|
||
OpcodeName := OpcodeName + OPCODE_NAME[Instr.OpCode.Opcode];
|
||
OpcodeName := OpcodeName + OPCODE_SUFFIX[Instr.OpCode.Suffix];
|
||
if Instr.Flags * [ifOnly32, ifOnly64, ifOnlyVex] <> [] 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;
|
||
|
||
procedure TX86AsmDecoder.Disassemble(var AAddress: Pointer; out
|
||
ACodeBytes: String; out ACode: String);
|
||
var
|
||
AnInfo: TDbgInstInfo;
|
||
begin
|
||
Disassemble(AAddress, ACodeBytes, ACode, AnInfo);
|
||
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;
|
||
|
||
function TX86AsmDecoder.IsAfterCallInstruction(AnAddress: TDBGPtr): boolean;
|
||
const
|
||
MAX_RET_LEN = 10;
|
||
var
|
||
BytesRead: Cardinal;
|
||
i: Integer;
|
||
instr: TDbgAsmInstruction;
|
||
begin
|
||
BytesRead := MAX_RET_LEN;
|
||
Result := (AnAddress > MAX_RET_LEN) and ReadCodeAt(AnAddress - MAX_RET_LEN, BytesRead) and
|
||
(BytesRead = MAX_RET_LEN);
|
||
if not Result then begin
|
||
BytesRead := 5;
|
||
Result := (AnAddress > MAX_RET_LEN) and ReadCodeAt(AnAddress - MAX_RET_LEN, BytesRead) and
|
||
(BytesRead = MAX_RET_LEN);
|
||
end;
|
||
if not Result then
|
||
exit;
|
||
|
||
// can be a false positive
|
||
Result := (FCodeBin[MAX_RET_LEN-3] in [$9A, $E8]) or (FCodeBin[MAX_RET_LEN-5] in [$9A, $E8]);
|
||
if Result then
|
||
exit;
|
||
|
||
for i := 2 to 6 do
|
||
if (FCodeBin[MAX_RET_LEN - i] = $FF) and
|
||
(FCodeBin[MAX_RET_LEN + 1 - i] and $38 in [$10, $18])
|
||
then begin
|
||
instr := GetInstructionInfo(AnAddress - i);
|
||
Result := instr.IsCallInstruction;
|
||
exit;
|
||
end;
|
||
if (FCodeBin[MAX_RET_LEN-10] = $FF) and
|
||
(FCodeBin[MAX_RET_LEN + 1 - 10] and $38 in [$10, $18])
|
||
then begin
|
||
instr := GetInstructionInfo(AnAddress-10);
|
||
Result := instr.IsCallInstruction;
|
||
exit;
|
||
end;
|
||
end;
|
||
|
||
function TX86AsmDecoder.UnwindFrame(var AnAddress, AStackPtr, AFramePtr: TDBGPtr; AQuick: boolean;
|
||
ARegisterValueList: TDbgRegisterValueList): boolean;
|
||
|
||
function IsRegister(Val, Reg: String): boolean;
|
||
begin
|
||
Result := (Length(Val) = Length(Reg) + 1) and (Length(val) >= 2) and (val[1] in ['r', 'e']) and (strlcomp(@Val[2], PChar(Reg), Length(Reg)) = 0);
|
||
end;
|
||
function RegisterSize(Reg: String): Cardinal;
|
||
begin
|
||
Result := 4;
|
||
if (Reg <> '') and (Reg[1] = 'r') then
|
||
Result := 8;
|
||
end;
|
||
function CleanRegisterName(Reg: String): String;
|
||
var
|
||
l: Integer;
|
||
begin
|
||
Result := Reg;
|
||
l := Length(reg);
|
||
if (l > 2) and (Reg[l-1] = '%') and (Reg[l] = 's') then Delete(Result, l-1, 2);
|
||
end;
|
||
function FullRegisterName(Reg: String): String;
|
||
var
|
||
l: Integer;
|
||
pre: String;
|
||
begin
|
||
Result := '';
|
||
Reg := CleanRegisterName(Reg);
|
||
l := Length(reg);
|
||
|
||
if (l < 2) then
|
||
Exit;
|
||
|
||
if (Reg[1] = 'r') and (Reg[2] in ['0'..'9']) then begin
|
||
if (l >=3) and (Reg[3] in ['0'..'9']) then
|
||
l := 3+1
|
||
else
|
||
l := 2+1;
|
||
Result := Reg;
|
||
Delete(Result, l, Length(Reg));
|
||
exit;
|
||
end;
|
||
|
||
if (l > 3) then
|
||
Exit;
|
||
if FProcess.Mode = dm32
|
||
then pre := 'e'
|
||
else pre := 'r';
|
||
|
||
case Reg[l] of
|
||
'l', 'h': case Reg[l-1] of
|
||
'a', 'b', 'c', 'd': // ah al
|
||
if l = 2 then Result := pre + Reg[l-1] + 'x';
|
||
end;
|
||
'x': case Reg[l-1] of
|
||
'a', 'b', 'c', 'd': // eax rax ax
|
||
if l = 2 then Result := pre + Reg
|
||
else
|
||
if Reg[1] in ['r', 'e'] then Result := pre +Reg[l-1] + Reg[l];
|
||
end;
|
||
'p': case Reg[l-1] of
|
||
's', 'b', 'i': // Rsp Esp Eip Ebp
|
||
if l = 2 then Result := pre + Reg
|
||
else
|
||
if Reg[1] in ['r', 'e'] then Result := pre +Reg[l-1] + Reg[l];
|
||
end;
|
||
'i':case Reg[l-1] of
|
||
'd', 's': // esi edi
|
||
if l = 2 then Result := pre + Reg
|
||
else
|
||
if Reg[1] in ['r', 'e'] then Result := pre +Reg[l-1] + Reg[l];
|
||
end;
|
||
//'s':
|
||
end;
|
||
end;
|
||
procedure ClearRegister(Reg: String);
|
||
var
|
||
r: TDbgRegisterValue;
|
||
begin
|
||
Reg := CleanRegisterName(Reg);
|
||
r := ARegisterValueList.FindRegisterByName(Reg);
|
||
if r <> nil then ARegisterValueList.Remove(r);
|
||
Reg := FullRegisterName(Reg);
|
||
if Reg <> '' then begin
|
||
r := ARegisterValueList.FindRegisterByName(Reg);
|
||
if r <> nil then ARegisterValueList.Remove(r);
|
||
end;
|
||
end;
|
||
|
||
|
||
var
|
||
NewAddr, NewStack, NewFrame: TDBGPtr;
|
||
CurAddr: PByte;
|
||
|
||
function ValueFromOperand(constref Oper: TInstructionOperand; out AVal: TDBGPtr; IsLea: Boolean = False): boolean;
|
||
var
|
||
OpVal: Int64;
|
||
Src: TDBGPtr;
|
||
RSize: Cardinal;
|
||
FullName: String;
|
||
r: TDbgRegisterValue;
|
||
begin
|
||
AVal := 0;
|
||
Result := True;
|
||
if (Oper.ByteCount2 <> 0) then
|
||
exit(False);
|
||
|
||
if (Oper.ByteCount = 0)
|
||
then begin
|
||
if IsLea then exit(False);
|
||
if (IsRegister(Oper.Value, 'bp')) then
|
||
AVal := NewFrame
|
||
else
|
||
if (IsRegister(Oper.Value, 'sp')) then
|
||
AVal := NewStack
|
||
else
|
||
begin
|
||
FullName := FullRegisterName(Oper.Value);
|
||
if (LowerCase(FullName) = LowerCase(Oper.Value)) then begin
|
||
r := ARegisterValueList.FindRegisterByName(FullName);
|
||
if r <> nil then begin
|
||
AVal := r.NumValue;
|
||
Exit(True);
|
||
end;
|
||
end;
|
||
exit(False);
|
||
end;
|
||
end
|
||
else
|
||
if (Oper.ByteCount <> 0)
|
||
then begin
|
||
if IsLea and not (ofMemory in Oper.Flags) then exit(False);
|
||
OpVal := ValueFromMem(CurAddr[Oper.CodeIndex], Oper.ByteCount, Oper.FormatFlags);
|
||
|
||
if (IsRegister(Oper.Value, 'bp%s')) then
|
||
{$PUSH}{$R-}{$Q-}
|
||
AVal := NewFrame + OpVal
|
||
{$POP}
|
||
else
|
||
if (IsRegister(Oper.Value, 'sp%s')) then
|
||
{$PUSH}{$R-}{$Q-}
|
||
AVal := NewStack + OpVal
|
||
{$POP}
|
||
else
|
||
if (Oper.Value = '%s') and (not(ofMemory in Oper.Flags))
|
||
then begin
|
||
AVal := TDBGPtr(OpVal) // constant
|
||
end
|
||
else
|
||
if (ofMemory in Oper.Flags) then begin
|
||
FullName := FullRegisterName(Oper.Value);
|
||
AVal := 0;
|
||
if (LowerCase(FullName)+'%s' = LowerCase(Oper.Value)) then begin
|
||
r := ARegisterValueList.FindRegisterByName(FullName);
|
||
if r = nil then
|
||
exit(False);
|
||
|
||
AVal := r.NumValue;
|
||
{$PUSH}{$R-}{$Q-}
|
||
if (AVal >= NewStack) and (AVal < NewStack + 8192) then // only trust data from the stack
|
||
AVal := AVal + OpVal
|
||
else
|
||
AVal := 0;
|
||
{$POP}
|
||
end;
|
||
if AVal = 0 then
|
||
exit(False);
|
||
end
|
||
else
|
||
exit(False);
|
||
end
|
||
else
|
||
exit(False);
|
||
|
||
if (ofMemory in Oper.Flags) and not IsLea then begin
|
||
Src := AVal;
|
||
AVal := 0;
|
||
RSize := RegisterSize(Oper.Value);
|
||
if not FProcess.ReadData(Src, RSize, AVal, RSize) then
|
||
exit(False);
|
||
end;
|
||
end;
|
||
|
||
const
|
||
MAX_SEARCH_ADDR = 8000;
|
||
MAX_SEARCH_CNT = 400;
|
||
MAX_ADDR_DONE_BLOCKS = 10;
|
||
MAX_FORWARD_ADDR = 5;
|
||
var
|
||
AddressDoneBlocks: array [0..MAX_ADDR_DONE_BLOCKS] of record
|
||
First, Last: TDBGPtr;
|
||
end;
|
||
CurAddressDoneBlock: integer;
|
||
MaxAddrCurrentBlock: TDBGPtr;
|
||
ConditionalForwardAddr: array [0..MAX_FORWARD_ADDR+1] of TDBGPtr;
|
||
CurConditionalForwardAddr: integer;
|
||
|
||
function AddrWasDone(AnAddr: TDBGPtr): boolean; inline;
|
||
var
|
||
i: Integer;
|
||
begin
|
||
i := CurAddressDoneBlock;
|
||
Result := (AnAddr >= AddressDoneBlocks[i].First) and (AnAddr < NewAddr);
|
||
while (not Result) and (i > 0) do begin
|
||
dec(i);
|
||
Result := (AnAddr >= AddressDoneBlocks[i].First) and (AnAddr < AddressDoneBlocks[i].Last);
|
||
end;
|
||
end;
|
||
|
||
function NextDoneAddrFor(AnAddr: TDBGPtr): TDBGPtr; inline;
|
||
var
|
||
i: Integer;
|
||
begin
|
||
Result := high(TDBGPtr);
|
||
i := CurAddressDoneBlock - 1;
|
||
while (i >= 0) do begin
|
||
if (AnAddr < AddressDoneBlocks[i].First) and
|
||
(Result > AddressDoneBlocks[i].First)
|
||
then
|
||
Result := AddressDoneBlocks[i].First;
|
||
dec(i);
|
||
end;
|
||
end;
|
||
|
||
procedure FinishCurAddrBlock; inline;
|
||
begin
|
||
if CurAddressDoneBlock < MAX_ADDR_DONE_BLOCKS then begin
|
||
AddressDoneBlocks[CurAddressDoneBlock].Last := NewAddr;
|
||
inc(CurAddressDoneBlock);
|
||
AddressDoneBlocks[CurAddressDoneBlock].First := high(TDBGPtr);
|
||
end
|
||
else
|
||
if NewAddr > AddressDoneBlocks[CurAddressDoneBlock].Last then begin
|
||
AddressDoneBlocks[CurAddressDoneBlock].Last := NewAddr;
|
||
end;
|
||
end;
|
||
procedure StartNextAddrBlock; inline;
|
||
begin
|
||
if CurAddressDoneBlock < MAX_ADDR_DONE_BLOCKS then
|
||
AddressDoneBlocks[CurAddressDoneBlock].First := NewAddr
|
||
else
|
||
if NewAddr < AddressDoneBlocks[CurAddressDoneBlock].First then
|
||
AddressDoneBlocks[CurAddressDoneBlock].First := NewAddr;
|
||
|
||
MaxAddrCurrentBlock := NextDoneAddrFor(NewAddr);
|
||
end;
|
||
|
||
procedure CheckConditionalForwAddr; inline;
|
||
var
|
||
j, i: Integer;
|
||
begin
|
||
j := 0;
|
||
for i := 0 to CurConditionalForwardAddr do
|
||
if (ConditionalForwardAddr[i] >= NewAddr) or
|
||
(ConditionalForwardAddr[i] < AddressDoneBlocks[CurAddressDoneBlock].First)
|
||
then begin
|
||
ConditionalForwardAddr[j] := ConditionalForwardAddr[i];
|
||
inc(j);
|
||
end;
|
||
CurConditionalForwardAddr := j - 1;
|
||
end;
|
||
|
||
procedure AddConditionalForwAddr(AnAddr: TDBGPtr); inline;
|
||
var
|
||
i, j: Integer;
|
||
begin
|
||
i := CurConditionalForwardAddr;
|
||
while (i >= 0) and (AnAddr <> ConditionalForwardAddr[i]) do
|
||
dec(i);
|
||
if i >= 0 then
|
||
exit;
|
||
|
||
if CurConditionalForwardAddr < MAX_FORWARD_ADDR then begin
|
||
inc(CurConditionalForwardAddr);
|
||
ConditionalForwardAddr[CurConditionalForwardAddr] := AnAddr;
|
||
end
|
||
else begin
|
||
j := 0;
|
||
for i := 0 to CurConditionalForwardAddr do
|
||
if (ConditionalForwardAddr[i] >= NewAddr) or
|
||
(ConditionalForwardAddr[i] < AddressDoneBlocks[CurAddressDoneBlock].First)
|
||
then begin
|
||
ConditionalForwardAddr[j] := ConditionalForwardAddr[i];
|
||
inc(j);
|
||
end;
|
||
CurConditionalForwardAddr := j - 1;
|
||
if CurConditionalForwardAddr < MAX_FORWARD_ADDR then
|
||
inc(CurConditionalForwardAddr);
|
||
ConditionalForwardAddr[CurConditionalForwardAddr] := AnAddr;
|
||
end;
|
||
end;
|
||
|
||
var
|
||
MaxAddr, StartStack, Tmp: TDBGPtr;
|
||
BackwardJumpAddress: TDBGPtr;
|
||
Cnt: Integer;
|
||
instr: TX86AsmInstruction;
|
||
RSize: Cardinal;
|
||
Val: Int64;
|
||
ClearRecValList, ForceDifferentBranch: Boolean;
|
||
FullName: String;
|
||
begin
|
||
Result := False;
|
||
NewAddr := AnAddress;
|
||
NewStack := AStackPtr;
|
||
NewFrame := AFramePtr;
|
||
StartStack := AStackPtr;
|
||
CurConditionalForwardAddr := -1;
|
||
BackwardJumpAddress := 0;
|
||
|
||
{$PUSH}{$R-}{$Q-}
|
||
MaxAddr := AnAddress + MAX_SEARCH_ADDR;
|
||
{$POP}
|
||
Cnt := MAX_SEARCH_CNT;
|
||
if AQuick then Cnt := 10;
|
||
|
||
CurAddressDoneBlock := 0;
|
||
AddressDoneBlocks[CurAddressDoneBlock].First := AnAddress;
|
||
MaxAddrCurrentBlock := MaxAddr;
|
||
|
||
ClearRecValList := False;
|
||
ForceDifferentBranch := False;
|
||
while (Cnt > 0) do begin
|
||
if ClearRecValList then ARegisterValueList.Clear;
|
||
|
||
if ForceDifferentBranch or (NewAddr >= MaxAddr) or( NewAddr > MaxAddrCurrentBlock) then begin
|
||
CheckConditionalForwAddr;
|
||
FinishCurAddrBlock;
|
||
while (CurConditionalForwardAddr >= 0) and
|
||
AddrWasDone(ConditionalForwardAddr[CurConditionalForwardAddr])
|
||
do
|
||
dec(CurConditionalForwardAddr);
|
||
if (CurConditionalForwardAddr >= 0) then begin
|
||
NewAddr := ConditionalForwardAddr[CurConditionalForwardAddr];
|
||
dec(CurConditionalForwardAddr);
|
||
end
|
||
else
|
||
if (BackwardJumpAddress > 0) and (not AddrWasDone(BackwardJumpAddress)) then begin
|
||
NewAddr := BackwardJumpAddress;
|
||
BackwardJumpAddress := 0;
|
||
end
|
||
else
|
||
exit;
|
||
StartNextAddrBlock;
|
||
ARegisterValueList.Clear;
|
||
end;
|
||
ForceDifferentBranch := False;
|
||
|
||
dec(Cnt);
|
||
instr := TX86AsmInstruction(GetInstructionInfo(NewAddr));
|
||
if instr.InstructionLength <= 0 then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewAddr := NewAddr + instr.InstructionLength;
|
||
{$POP}
|
||
CurAddr := @instr.FCodeBin[0];
|
||
|
||
ClearRecValList := True;
|
||
case instr.X86OpCode of
|
||
OPret:
|
||
begin
|
||
ClearRecValList := False;
|
||
if instr.X86Instruction.OperCnt > 1 then begin
|
||
exit;
|
||
end;
|
||
|
||
Val := 0;
|
||
if instr.X86Instruction.OperCnt = 1 then
|
||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags);
|
||
NewAddr := 0;
|
||
if FProcess.Mode = dm32 then begin
|
||
if not FProcess.ReadData(NewStack, 4, NewAddr, RSize) then
|
||
exit;
|
||
inc(NewStack, 4 + Val);
|
||
end
|
||
else begin
|
||
if not FProcess.ReadData(NewStack, 8, NewAddr, RSize) then
|
||
exit;
|
||
inc(NewStack, 8 + Val);
|
||
end;
|
||
Result := True;
|
||
AnAddress := NewAddr;
|
||
AStackPtr := NewStack;
|
||
AFramePtr := NewFrame;
|
||
exit;
|
||
end;
|
||
OPpush:
|
||
begin
|
||
ClearRecValList := False;
|
||
if AQuick then
|
||
exit;
|
||
if (instr.X86Instruction.OperCnt <> 1) or
|
||
IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') or
|
||
IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
|
||
then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewStack := NewStack - RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||
{$POP}
|
||
end;
|
||
OPpusha:
|
||
begin
|
||
ClearRecValList := False;
|
||
if (FProcess.Mode <> dm32) or (instr.X86Instruction.OpCode.Suffix <> OPSx_d) then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
// push 8 registers
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewStack := NewStack - (8*4);
|
||
{$POP}
|
||
end;
|
||
OPpushf:
|
||
begin
|
||
ClearRecValList := False;
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
OPpopa, OPpopad:
|
||
begin
|
||
ClearRecValList := False;
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
OPpop:
|
||
begin
|
||
if instr.X86Instruction.OperCnt <> 1 then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
ClearRecValList := False;
|
||
ClearRegister(instr.X86Instruction.Operand[1].Value);
|
||
if not(instr.X86Instruction.Operand[1].Value[1] in ['e', 'r'])
|
||
then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp')
|
||
then begin
|
||
if NewStack < StartStack then
|
||
exit;
|
||
NewFrame := 0;
|
||
RSize := RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||
if not FProcess.ReadData(NewStack, RSize, NewFrame, RSize) then
|
||
exit;
|
||
end
|
||
else
|
||
if NewStack >= StartStack then begin
|
||
Tmp := 0;
|
||
RSize := RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||
if FProcess.ReadData(NewStack, RSize, Tmp, RSize) then begin
|
||
FullName := LowerCase(FullRegisterName(instr.X86Instruction.Operand[1].Value));
|
||
ARegisterValueList.DbgRegisterAutoCreate[FullName].SetValue(Tmp, IntToStr(Tmp), RSize, 0);
|
||
end;
|
||
end;
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewStack := NewStack + RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||
{$POP}
|
||
end;
|
||
OPleave:
|
||
begin
|
||
ClearRecValList := False;
|
||
NewStack := NewFrame;
|
||
NewFrame := 0;
|
||
if FProcess.Mode = dm32 then begin
|
||
if not FProcess.ReadData(NewStack, 4, NewFrame, RSize) then
|
||
exit;
|
||
inc(NewStack, 4);
|
||
end
|
||
else begin
|
||
if not FProcess.ReadData(NewStack, 8, NewFrame, RSize) then
|
||
exit;
|
||
inc(NewStack, 8);
|
||
end;
|
||
end;
|
||
OPmov:
|
||
begin
|
||
if instr.X86Instruction.OperCnt <> 2 then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
ClearRecValList := False;
|
||
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and
|
||
not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
|
||
then begin
|
||
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
NewStack := Tmp;
|
||
end
|
||
else
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') and
|
||
not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
|
||
then begin
|
||
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then
|
||
NewFrame := 0
|
||
else
|
||
NewFrame := Tmp;
|
||
end
|
||
else begin
|
||
FullName := LowerCase(FullRegisterName(instr.X86Instruction.Operand[1].Value));
|
||
if ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
|
||
RSize := RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||
ARegisterValueList.DbgRegisterAutoCreate[FullName].SetValue(Tmp, IntToStr(Tmp), RSize, 0);
|
||
end
|
||
else
|
||
ClearRegister(instr.X86Instruction.Operand[1].Value);
|
||
end;
|
||
end;
|
||
OPlea:
|
||
begin
|
||
if instr.X86Instruction.OperCnt <> 2 then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
ClearRecValList := False;
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp')
|
||
then begin
|
||
if (Instr.X86Instruction.Operand[2].ByteCount = 0) or
|
||
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
|
||
not(ofMemory in Instr.X86Instruction.Operand[2].Flags)
|
||
then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
|
||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags);
|
||
if (IsRegister(instr.X86Instruction.Operand[2].Value, 'sp%s')) then begin
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewFrame := NewStack + Val;
|
||
{$POP}
|
||
end
|
||
else
|
||
if (IsRegister(instr.X86Instruction.Operand[2].Value, 'bp%s')) then begin
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewFrame := NewFrame + Val;
|
||
{$POP}
|
||
end
|
||
else
|
||
if ValueFromOperand(instr.X86Instruction.Operand[2], Tmp, True) then begin
|
||
NewFrame := Tmp;
|
||
end;
|
||
end
|
||
else
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
|
||
then begin
|
||
if (Instr.X86Instruction.Operand[2].ByteCount = 0) or
|
||
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
|
||
not(ofMemory in Instr.X86Instruction.Operand[2].Flags)
|
||
then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
|
||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags);
|
||
if (IsRegister(instr.X86Instruction.Operand[2].Value, 'sp%s')) then begin
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewStack := NewStack + Val;
|
||
{$POP}
|
||
end
|
||
else
|
||
if (IsRegister(instr.X86Instruction.Operand[2].Value, 'bp%s')) then begin
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewStack := NewFrame + Val;
|
||
{$POP}
|
||
end
|
||
else
|
||
if ValueFromOperand(instr.X86Instruction.Operand[2], Tmp, True) then begin
|
||
NewStack := Tmp;
|
||
end
|
||
else begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
end
|
||
else begin
|
||
FullName := LowerCase(FullRegisterName(instr.X86Instruction.Operand[1].Value));
|
||
if (Instr.X86Instruction.Operand[2].ByteCount = 0) or
|
||
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
|
||
not(ofMemory in Instr.X86Instruction.Operand[2].Flags)
|
||
then
|
||
ClearRegister(instr.X86Instruction.Operand[1].Value)
|
||
else begin
|
||
if ValueFromOperand(instr.X86Instruction.Operand[2], Tmp, True) then begin
|
||
RSize := RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||
ARegisterValueList.DbgRegisterAutoCreate[FullName].SetValue(Tmp, IntToStr(Tmp), RSize, 0);
|
||
end
|
||
else
|
||
ClearRegister(instr.X86Instruction.Operand[1].Value)
|
||
end;
|
||
end;
|
||
end;
|
||
OPadd:
|
||
begin
|
||
if instr.X86Instruction.OperCnt <> 2 then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
ClearRecValList := False;
|
||
ClearRegister(instr.X86Instruction.Operand[1].Value);
|
||
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and
|
||
not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
|
||
then begin
|
||
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewStack := NewStack + int64(Tmp);
|
||
{$POP}
|
||
end;
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') and
|
||
not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
|
||
then begin
|
||
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewFrame := NewFrame + int64(Tmp);
|
||
{$POP}
|
||
end;
|
||
end;
|
||
OPsub:
|
||
begin
|
||
if instr.X86Instruction.OperCnt <> 2 then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
ClearRecValList := False;
|
||
ClearRegister(instr.X86Instruction.Operand[1].Value);
|
||
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and
|
||
not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
|
||
then begin
|
||
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewStack := NewStack - int64(Tmp);
|
||
{$POP}
|
||
end;
|
||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') and
|
||
not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
|
||
then begin
|
||
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
{$PUSH}{$R-}{$Q-}
|
||
NewFrame := NewFrame - int64(Tmp);
|
||
{$POP}
|
||
end;
|
||
end;
|
||
OPj__:
|
||
if (not AQuick) and
|
||
(instr.X86Instruction.OperCnt = 1) and
|
||
(instr.X86Instruction.Operand[1].Value = '%s') and
|
||
(Instr.X86Instruction.Operand[1].ByteCount > 0) and
|
||
(Instr.X86Instruction.Operand[1].ByteCount2 = 0)
|
||
then
|
||
begin
|
||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags);
|
||
{$PUSH}{$R-}{$Q-}
|
||
Tmp := NewAddr + Val;
|
||
{$POP}
|
||
if Val > 0 then begin
|
||
if (Tmp < MaxAddr) and (not AddrWasDone(Tmp)) then
|
||
AddConditionalForwAddr(Tmp);
|
||
end
|
||
else begin
|
||
if ((BackwardJumpAddress = 0) or (Tmp < BackwardJumpAddress)) and
|
||
(not AddrWasDone(Tmp))
|
||
then
|
||
BackwardJumpAddress := Tmp;
|
||
end;
|
||
end;
|
||
OPjmp:
|
||
begin
|
||
if AQuick then
|
||
exit;
|
||
if instr.X86Instruction.OperCnt <> 1 then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
if (instr.X86Instruction.Operand[1].Value <> '%s') then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
if (Instr.X86Instruction.Operand[1].ByteCount = 0) or
|
||
(Instr.X86Instruction.Operand[1].ByteCount2 <> 0)
|
||
then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
|
||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags);
|
||
{$PUSH}{$R-}{$Q-}
|
||
Tmp := NewAddr + Val;
|
||
{$POP}
|
||
if (Val < 0) then begin
|
||
CheckConditionalForwAddr;
|
||
if (CurConditionalForwardAddr >= 0) then begin
|
||
FinishCurAddrBlock;
|
||
NewAddr := ConditionalForwardAddr[CurConditionalForwardAddr];
|
||
dec(CurConditionalForwardAddr);
|
||
StartNextAddrBlock;
|
||
ClearRecValList := True;
|
||
|
||
if ((BackwardJumpAddress = 0) or (Tmp < BackwardJumpAddress)) and
|
||
(not AddrWasDone(Tmp))
|
||
then
|
||
BackwardJumpAddress := Tmp;
|
||
continue;
|
||
end;
|
||
|
||
end;
|
||
|
||
if AddrWasDone(Tmp) then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
|
||
FinishCurAddrBlock;
|
||
NewAddr := Tmp;
|
||
StartNextAddrBlock;
|
||
end;
|
||
OPjmpe, OPint, OPint1, OPint3: begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
OPtest, OPtpause, OPnop, OPcmp, OPcmps:
|
||
ClearRecValList := False;
|
||
else
|
||
begin
|
||
if (instr.X86Instruction.OperCnt >= 1) and
|
||
(not(ofMemory in Instr.X86Instruction.Operand[1].Flags)) and
|
||
( IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') or
|
||
IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
|
||
)
|
||
then begin
|
||
ForceDifferentBranch := True;
|
||
continue;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
if ClearRecValList then ARegisterValueList.Clear;
|
||
end;
|
||
|
||
{ TDbgStackUnwinderIntelDisAssembler }
|
||
|
||
function TDbgStackUnwinderIntelDisAssembler.Unwind(AFrameIndex: integer;
|
||
var CodePointer, StackPointer, FrameBasePointer: TDBGPtr;
|
||
ACurrentFrame: TDbgCallstackEntry; out ANewFrame: TDbgCallstackEntry
|
||
): TTDbgStackUnwindResult;
|
||
var
|
||
ARegisterValueList: TDbgRegisterValueList;
|
||
begin
|
||
ANewFrame := nil;
|
||
Result := suFailed;
|
||
ARegisterValueList := TDbgRegisterValueList.Create(True);
|
||
if (ACurrentFrame <> nil) and (ACurrentFrame.RegisterValueList <> nil) then
|
||
ARegisterValueList.Assign(ACurrentFrame.RegisterValueList);
|
||
|
||
if Process.Disassembler.UnwindFrame(CodePointer, StackPointer, FrameBasePointer, False, ARegisterValueList)
|
||
then begin
|
||
ANewFrame := TDbgCallstackEntry.Create(Thread, AFrameIndex, FrameBasePointer, CodePointer);
|
||
ANewFrame.RegisterValueList.Assign(ARegisterValueList);
|
||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[FNameIP].SetValue(CodePointer, IntToStr(CodePointer),AddressSize, FDwarfNumIP);
|
||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[FNameBP].SetValue(FrameBasePointer, IntToStr(FrameBasePointer),AddressSize, FDwarfNumBP);
|
||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[FNameSP].SetValue(StackPointer, IntToStr(StackPointer),AddressSize, FDwarfNumSP);
|
||
Result := suSuccess;
|
||
end;
|
||
ARegisterValueList.free
|
||
end;
|
||
|
||
|
||
initialization
|
||
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
||
end.
|