{ $Id$ } { --------------------------------------------------------------------------- fpdbgdisasx86.pp - Native Freepascal debugger - x86 Disassembler --------------------------------------------------------------------------- This unit contains a x86 disassembler for the Native Freepascal debugger --------------------------------------------------------------------------- @created(Mon Apr 22th WET 2006) @lastmod($Date$) @author(Marc Weustink ) *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * *************************************************************************** } unit FpDbgDisasX86; {$mode objfpc}{$H+} interface {.$define debug_OperandSize} {.$define verbose_string_instructions} uses SysUtils, FpDbgUtil, FpDbgInfo, DbgIntfBaseTypes, FpdMemoryTools; { 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 } procedure Disassemble(var AAddress: Pointer; const A64Bit: Boolean; out ACodeBytes: String; out ACode: String); implementation type TFlag = (flagRex, flagSib, flagModRM, rexB, rexX, rexR, rexW, preOpr, preAdr, preLock, preRep{N}, preRepNE); TFlags = set of TFlag; // Keep 8,16,32,64 together TOperandSize = (os8, os16, os32, os64, os48, os80, os128); TAddressSize = (as16, as32, as64); TRegisterType = (reg0, reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug, regX87); TModRMType = (modReg, modMem); TModRMTypes = set of TModRMType; const ADDRESS_BYTES: array[TAddressSize] of Byte = (2, 4, 8); OPERAND_BYTES: array[TOperandSize] of Byte = (1, 2, 4, 8, 6, 10, 16); OPERAND_REG: array[os8..os64] of TRegisterType = (reg8, reg16, reg32, reg64); STD_REGS = [reg8..reg64]; type TOperandFlag = (ofMemory); TOperandFlags = set of TOperandFlag; procedure Disassemble(var AAddress: Pointer; const A64Bit: Boolean; out ACodeBytes: String; out ACode: String); var Code: PByte; CodeIdx: Byte; Operand: array[1..4] of record Value: String; Size: TOperandSize; ByteCount: Byte; ByteCount2: Byte; FormatFlags: THexValueFormatFlags; Flags: TOperandFlags; end; OperIdx: Byte; ModRMIdx: Byte; Opcode: String; Segment: String; Flags: TFlags; function Check32(const Opcode: String): String; begin // only valid in 32-bit mode if A64Bit then Result := '**' + Opcode + '**' else Result := Opcode; end; function Check64(const Opcode: String): String; begin // only valid in 64-bit mode if A64Bit then Result := Opcode else Result := '**' + Opcode + '**'; end; function Ignore64(const Opcode: String): String; begin // ignored in 64-bit mode if A64Bit then Result := '(' + Opcode + ')' else Result := Opcode; end; function CheckLock(const AOpcode: String): String; function CheckMem: boolean; var n: Byte; begin Result := True; for n := 1 to OperIdx do if ofMemory in Operand[n].Flags then Exit; Result := False; end; begin if (preLock in Flags) and CheckMem then begin Exclude(Flags, preLock); Result := 'lock ' + AOpcode; Exit; end; Result := AOpcode; end; function CheckRepeat(const AOpcode: String): String; begin if preRep in Flags then begin Exclude(Flags, preRep); Result := 'rep ' + AOpcode; Exit; end; Result := AOpcode; end; function CheckRepeatX(const AOpcode: String): String; begin if preRep in Flags then begin Exclude(Flags, preRep); Result := 'repe ' + AOpcode; Exit; end; if preRepNE in Flags then begin Exclude(Flags, preRepNE); Result := 'repne ' + AOpcode; Exit; end; Result := AOpcode; end; //=================== function DecodePrefix(const AOpcode, AOpcodeRep, AOpcodeOpr, AOpcodeRepNE: string): Integer; var S: String; begin if preRep in Flags then begin S := AOpcodeRep; Exclude(Flags, preRep); Result := 1; end else if preOpr in Flags then begin S := AOpcodeOpr; Exclude(Flags, preOpr); Result := 2; end else if preRepNE in Flags then begin S := AOpcodeRepNE; Exclude(Flags, preRepNE); Result := 3; end else begin S := AOpcode; Result := 0; end; if S = '' then Result := -1 else Opcode := S; end; function AddressSize32: TAddressSize; begin // effective address size for default 32 operand size if A64Bit 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 OperandSize32: TOperandSize; begin // effective operand size for default 32 operand size if rexW in FLags then begin Result := os64; end else begin if preOpr in Flags then Result := os16 else Result := os32; end; end; procedure AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []; AByteCount2: Byte = 0); begin Inc(OperIdx); if OperIdx > High(Operand) then begin Log('AddOperand: Only %d operands supported, got %d', [High(Operand), OperIdx]); Exit; end; Operand[OperIdx].Size := ASize; Operand[OperIdx].ByteCount := AByteCount; Operand[OperIdx].ByteCount2 := AByteCount2; Operand[OperIdx].FormatFlags := AFormatFlags; Operand[OperIdx].Value := AValue; Operand[OperIdx].Flags := AFlags; end; procedure AddOperand(const AValue: String; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []); begin AddOperand(AValue, OperandSize32, AByteCount, AFormatFlags, AFlags); end; function SizeReg32(const AReg: String; ASize: TOperandSize): String; begin // prefix a reg for default 32 operand size case ASize of os64: Result := 'r' + AReg; os32: Result := 'e' + AReg; else Result := AReg; end; end; function SizeReg32(const AReg: String): String; begin Result := SizeReg32(AReg, OperandSize32); end; function StdCond(AIndex: Byte): String; const COND: array[0..$F] of String = ('o', 'no', 'b', 'nb', 'z', 'nz', 'be', 'nbe', 's', 'ns', 'p', 'np', 'l', 'nl', 'le', 'nle'); begin Result := COND[AIndex and $F]; end; function StdReg(AIndex: Byte; AType: TRegisterType; AExtReg: Boolean): String; const REGS: array[0..7] of string = ('ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di'); REG8_: array[0..7] of String = ('al', 'cl', 'dl', 'bl', 'ah', 'ch', 'dh', 'bh'); REG8r: array[0..7] of String = ('al', 'cl', 'dl', 'bl', 'spl', 'bpl', 'sil', 'dil'); SREG: array[0..7] of String = ('es', 'cs', 'ss', 'ds', 'fs', 'gs', '**', '**'); POSTFIX: array[reg16..reg64] of String = ('w', 'd', ''); OSMAP: array[reg8..reg64] of TOperandSize = (os8, os16, os32, os64); begin AIndex := AIndex and $7; case AType of reg8: begin if AExtReg then begin Result := Format('r%db', [8 + AIndex]); end else begin if flagRex in Flags then Result := REG8r[AIndex] else Result := REG8_[AIndex]; end; end; reg16..reg64: begin if AExtReg then Result := Format('r%d', [8 + AIndex]) + POSTFIX[AType] else Result := SizeReg32(REGS[AIndex], OSMAP[AType]); end; regX87: begin Result := Format('st(%d)', [AIndex]); end; regMmx: begin Result := Format('mmx%d', [AIndex]); end; regXmm: begin if AExtReg then Inc(AIndex, 8); Result := Format('xmm%d', [AIndex]); end; regSegment: begin Result := SREG[AIndex]; end; regControl: begin if AExtReg then Inc(AIndex, 8); Result := Format('cr%d', [AIndex]); end; regDebug: begin if AExtReg then Inc(AIndex, 8); Result := Format('dr%d', [AIndex]); end; end; end; function StdReg(AIndex: Byte): String; begin Result := StdReg(AIndex, OPERAND_REG[OperandSize32], rexR in Flags); end; procedure AddStdReg(AIndex: Byte; AType: TRegisterType; AExtReg: Boolean); const // reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug, regX87 REGSIZE: array[Boolean, reg8..High(TRegisterType)] of TOperandSize = ( {32}(os8, os16, os32, os64, os64, os128, os16, os32, os32, os80), {64}(os8, os16, os32, os64, os64, os128, os16, os64, os64, os80) ); begin AddOperand(StdReg(AIndex, AType, AExtReg), REGSIZE[A64Bit, AType]); end; procedure AddStdReg(AIndex: Byte); begin AddOperand(StdReg(AIndex, OPERAND_REG[OperandSize32], rexR in Flags)); end; procedure AddModReg(AType: TRegisterType; ASize: TOperandSize); begin Include(Flags, flagModRM); AddOperand(StdReg(Code[ModRMIdx] shr 3, AType, False), ASize); end; procedure AddModReg(AType: TRegisterType; AExtReg: Boolean); begin Include(Flags, flagModRM); AddStdReg(Code[ModRMIdx] shr 3, AType, AExtReg); end; procedure AddModReg; begin Include(Flags, flagModRM); AddStdReg(Code[ModRMIdx] shr 3); end; procedure AddModRM(AReqTypes: TModRMTypes; ASize: TOperandSize; AType: TRegisterType); var Mode, Rm: Byte; procedure Mem16; const REGS16: array[0..7] of string = ('bx+si', 'bx+di', 'bp+si', 'bp+di', 'si', 'di', 'bp', 'bx'); begin case Mode of 0: begin if rm = 6 // disp16 -> exeption to the regs then AddOperand('%s', ASize, 2, [hvfSigned, hvfIncludeHexchar], [ofMemory]) else AddOperand(REGS16[rm], ASize, 0, [], [ofMemory]); end; 1: AddOperand(REGS16[rm] + '%s', ASize, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]); 2: AddOperand(REGS16[rm] + '%s', ASize, 2, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]); end; end; var AddrSize: TAddressSize; Sib: record Scale, Index, Base: Byte; end; Oper: record Size: Byte; Flags: THexValueFormatFlags; Value: String; end; begin Include(Flags, flagModRM); Mode := Code[ModRMIdx] shr 6; Rm := Code[ModRMIdx] and $7; // Check for reg (mode = 3) first; if mode = 3 then begin if modReg in AReqTypes then AddStdReg(rm, AType, False) else AddOperand('**'); Exit; end; // Check if mem is allowed if not (modMem in AReqTypes) then begin AddOperand('**', 0, [], [ofMemory]); Exit; end; Oper.Size := 0; Oper.Flags := []; Oper.Value := ''; // Here only mem access AddrSize := AddressSize32; if AddrSize = as16 then begin Mem16; Exit; end; if rm = 4 then begin // sib folows Include(Flags, flagSib); sib.Scale := Code[ModRMIdx+1] shr 6; sib.Index := (Code[ModRMIdx+1] shr 3) and $7; sib.Base := Code[ModRMIdx+1] and $7; // base if (mode = 0) and (sib.Base = 5) then begin // disp32 Oper.Value := '%s'; Oper.Size := 4; if (sib.Index <> 4) or (rexX in Flags) then Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar] // [reg + base] else Oper.Flags := [hvfSigned, hvfIncludeHexchar]; // [base] end else begin if AddrSize = as32 then Oper.Value := StdReg(sib.Base, reg32, rexB in Flags) else Oper.Value := StdReg(sib.Base, reg64, 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 if AddrSize = as32 then Oper.Value := StdReg(sib.Index, reg32, rexX in Flags) + Oper.Value else Oper.Value := StdReg(sib.Index, reg64, rexX in Flags) + Oper.Value; end; end else begin // no sib if AddrSize = as32 then Oper.Value := StdReg(rm, reg32, rexB in Flags) else Oper.Value := StdReg(rm, reg64, rexB in Flags); end; case mode of 0: begin // exceptions to std encoding if rm = 5 then begin // disp32 if AddrSize = as64 then begin Oper.Value := 'rip%s'; Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]; end else begin Oper.Value := '%s'; Oper.Flags := [hvfSigned, hvfIncludeHexchar]; end; Oper.Size := 4; end; end; 1: begin Oper.Value := Oper.Value + '%s'; Oper.Size := 1; Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]; end; 2: begin Oper.Value := Oper.Value + '%s'; Oper.Size := 4; Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]; end; end; AddOperand(Oper.Value, ASize, Oper.Size, Oper.Flags, [ofMemory]); end; //=================== procedure AddAp; begin if OperandSize32 = os16 //XXXX:XXXX then AddOperand('$%1:s:%0:s', os32, 2, [], [], 2) else AddOperand('$%1:s:%0:s', os48, 4, [], [], 2) end; procedure AddCd_q; begin AddModReg(regControl, rexR in Flags); end; procedure AddDd_q; begin AddModReg(regDebug, rexR in Flags); end; procedure AddEb; begin AddModRM([modReg, modMem], os8, reg8); end; procedure AddEd; begin AddModRM([modReg, modMem], os32, reg32); end; procedure AddEd_q; begin if flagRex in Flags then AddModRM([modReg, modMem], os64, reg64) else AddModRM([modReg, modMem], os32, reg32); end; procedure AddEv; begin AddModRM([modReg, modMem], OperandSize32, OPERAND_REG[OperandSize32]); end; procedure AddEw; begin AddModRM([modReg, modMem], os16, reg16); end; procedure AddFv; begin case OperandSize32 of os64: AddOperand('rflags'); os32: AddOperand('eflags'); else AddOperand('flags'); end; end; procedure AddGb; begin AddModReg(reg8, rexR in Flags); end; procedure AddGd; begin AddModReg(reg32, rexR in Flags); end; procedure AddGd_q; begin if flagRex in Flags then AddModReg(reg64, rexR in Flags) else AddModReg(reg32, rexR in Flags); end; procedure AddGv; begin AddModReg; end; procedure AddGw; begin AddModReg(reg16, rexR in Flags); end; procedure AddGz; begin if OperandSize32 = os16 then AddModReg(reg16, rexR in Flags) else AddModReg(reg32, rexR in Flags); end; procedure AddIb; begin AddOperand('%s', os8, 1, [hvfIncludeHexchar]); end; procedure AddIv; begin AddOperand('%s', OPERAND_BYTES[OperandSize32], [hvfIncludeHexchar]); end; procedure AddIw; begin AddOperand('%s', os16, 2, [hvfIncludeHexchar]); end; procedure AddIz; begin if OperandSize32 = os16 then AddOperand('%s', os16, 2, [hvfIncludeHexchar]) else AddOperand('%s', os32, 4, [hvfIncludeHexchar]); end; procedure AddJb; begin AddOperand('%s', os8, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]); end; procedure AddJz; begin if OperandSize32 = os16 then AddOperand('%s', os16, 2, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]) else AddOperand('%s', os32, 4, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]); end; procedure AddM; begin AddModRM([modMem], OperandSize32, reg0 {do not care}); end; procedure AddMa; begin AddModRM([modMem], OperandSize32, reg0 {do not care}); end; procedure AddMb; begin AddModRM([modMem], os8, reg0 {do not care}); end; procedure AddMd; begin AddModRM([modMem], os32, reg0 {do not care}); end; procedure AddMd_q; begin if flagRex in Flags then AddModRM([modMem], os64, reg0 {do not care}) else AddModRM([modMem], os32, reg0 {do not care}); end; procedure AddMdq; begin AddModRM([modMem], os128, reg0 {do not care}) end; procedure AddMp; begin if OperandSize32 = os16 //XXXX:XXXX then AddModRM([modMem], os32, reg0 {do not care}) else AddModRM([modMem], os48, reg0 {do not care}); end; procedure AddMq; begin AddModRM([modMem], os64, reg0 {do not care}); end; procedure AddMs; begin if A64Bit then AddModRM([modMem], os80, reg0 {do not care}) else AddModRM([modMem], os48, reg0 {do not care}); end; procedure AddMw_Rv; begin if Code[ModRMIdx] shr 6 = 3 // mode = 3 -> reg then AddModRM([modReg], OperandSize32, OPERAND_REG[OperandSize32]) else AddModRM([modMem], os16, reg0 {do not care}); end; procedure AddOb; begin AddOperand('%s', os8, ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], [ofMemory]) end; procedure AddOv; begin AddOperand('%s', ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], [ofMemory]) end; procedure AddPd_q; begin if flagRex in Flags then AddModReg(regMmx, os64) else AddModReg(regMmx, os32); end; procedure AddPq; begin AddModReg(regMmx, False); end; procedure AddPRq; begin AddModRM([modReg], os64, regMmx); end; procedure AddQd; begin AddModRM([modReg, modMem], os32, regMmx); end; procedure AddQq; begin AddModRM([modReg, modMem], os64, regMmx); end; procedure AddRd_q; begin if A64Bit then AddModRM([modReg], os64, reg64) else AddModRM([modReg], os32, reg32); end; procedure AddSw; begin AddModReg(regSegment, False); end; procedure AddVd_q; begin if flagRex in Flags then AddModReg(regXmm, os64) else AddModReg(regXmm, os32); end; procedure AddVdq; begin AddModReg(regXmm, os128); end; procedure AddVdq_sd; begin AddModReg(regXmm, os64); // only lower 64 bit end; procedure AddVdq_ss; begin AddModReg(regXmm, os32); // only lower 32 bit end; procedure AddVpd; begin AddModReg(regXmm, os128); end; procedure AddVps; begin AddModReg(regXmm, os128); end; procedure AddVq; begin AddModReg(regXmm, os64); end; procedure AddVsd; begin AddModReg(regXmm, os64); end; procedure AddVss; begin AddModReg(regXmm, os32); end; procedure AddVRdq; begin AddModRM([modReg], os128, regXmm); end; procedure AddVRpd; begin AddModRM([modReg], os128, regXmm); end; procedure AddVRps; begin AddModRM([modReg], os128, regXmm); end; procedure AddVRq; begin AddModRM([modReg], os64, regXmm); end; procedure AddWdq; begin AddModRM([modReg, modMem], os128, regXmm); end; procedure AddWpd; begin AddModRM([modReg, modMem], os128, regXmm); end; procedure AddWps; begin AddModRM([modReg, modMem], os128, regXmm); end; procedure AddWq; begin AddModRM([modReg, modMem], os64, regXmm); end; procedure AddWsd; begin AddModRM([modReg, modMem], os64, regXmm); end; procedure AddWss; begin AddModRM([modReg, modMem], os32, regXmm); end; {$ifdef verbose_string_instructions} procedure AddXb; begin AddOperand('Xb'); end; procedure AddXv; begin AddOperand('Xv'); end; procedure AddXz; begin AddOperand('Xz'); end; procedure AddYb; begin AddOperand('Yb'); end; procedure AddYv; begin AddOperand('Yv'); end; procedure AddYz; begin AddOperand('Yz'); end; {$endif} //=================== procedure AddStdOperands(AIndex: Byte); begin case AIndex and $7 of 0: begin AddEb; AddGb; end; 1: begin AddEv; AddGv; end; 2: begin AddGb; AddEb; end; 3: begin AddGv; AddEv; end; 4: begin AddOperand('al', os8); AddIb; end; 5: begin AddOperand(SizeReg32('ax')); AddIz; end; else AddOperand('!!'); end; end; //=================== procedure DoX87; const INVALID = '**x87**'; RESERVED = '-x87-'; var Index: Byte; ModRM: Byte; procedure AddMem14_28Env; begin AddModRM([modMem], OperandSize32, reg0 {do not care}); end; procedure AddMem98_108Env; begin AddModRM([modMem], OperandSize32, reg0 {do not care}); end; procedure AddMem16; begin AddModRM([modMem], os16, reg0 {do not care}); end; procedure AddMem32; begin AddModRM([modMem], os32, reg0 {do not care}); end; procedure AddMem64; begin AddModRM([modMem], os64, reg0 {do not care}); end; procedure AddMem80; begin AddModRM([modMem], os80, reg0 {do not care}); end; procedure AddReg(AIndex: Byte); begin AddOperand(Format('st(%u)', [index]), os80); end; procedure AddReg0; begin AddOperand('st(0)', os80); end; procedure AddRegN; begin AddOperand(Format('st(%u)', [Code[ModRMIdx] and $7]), os80); end; procedure DoD8; const OPC: array[0..7] of String = ('fadd', 'fmul', 'fcom', 'fcomp', 'fsub', 'fsubr', 'fdiv', 'fdivr'); begin Opcode := OPC[Index]; case ModRM of $00..$BF: AddMem32 else AddReg0; AddRegN; end; end; procedure DoD9; const OPC: array[0..7] of String = ('fld', 'fxch', 'fst', 'fstp', 'fldenv', 'fldcw', 'fnstenv', 'fnstcw'); OPCx: array[0..$1F] of String = ( 'fchs', 'fabs', '', '', 'ftst', 'fxam', '', '', 'fld1', 'fldl2t', 'fldl2e', 'fldpi', 'fldlg2', 'fldln2', 'fldz', '', 'f2xm1', 'fyl2x', 'fptan', 'fpatan', 'fxtract', 'fprem1', 'fdecstp', 'fincstp', 'fprem', 'fyl2xp1', 'fsqrt', 'fsincos', 'frndint', 'fscale', 'fsin', 'fcos' ); begin case ModRM of $00..$BF: begin Opcode := OPC[Index]; case Index of 0, 2, 3: AddMem32; 1: Opcode := INVALID; 4, 6 : AddMem14_28Env; 5, 7: AddMem16; end; end; $C0..$CF: begin Opcode := OPC[Index]; AddReg0; AddRegN; end; $D0: begin Opcode := 'nop'; end; $D8..$DF: begin Opcode := RESERVED; end; $E0..$E1, $E4..$E5, $E8..$FF: begin Opcode := OPCx[ModRM and $1F]; end; else Opcode := INVALID; end; end; procedure DoDA; const OPC: array[0..7] of String = ('fiadd', 'fimull', 'ficom', 'ficomp', 'fisub', 'fisubr', 'fidiv', 'fidivr'); OPCx: array[0..3] of string = ('fcmovb', 'fcmove', 'fcmovbe', 'fcmovu'); begin case ModRM of $00..$BF: begin Opcode := OPC[Index]; AddMem32; end; $C0..$DF: begin Opcode := OPCx[Index]; AddReg0; AddRegN; end; $E9: begin Opcode := 'fucompp'; end; else Opcode := INVALID; end; end; procedure DoDB; const OPC: array[0..7] of String = ('fild', 'fisttp', 'fist', 'fistp', '', 'fld', '', 'fstp'); OPCx: array[0..7] of String = ('fcmovnb', 'fcmovne', 'fcmovnbe', 'fcmovnu', '', 'fucomi', 'fcomi', ''); begin case ModRM of $00..$BF: begin case Index of 0..3: begin Opcode := OPC[Index]; AddMem32; end; 5, 7: begin Opcode := OPC[Index]; AddMem80; end; else Opcode := INVALID; end; end; $C0..$DF, $E8..$F7: begin Opcode := OPCx[Index]; AddReg0; AddRegN; end; $E0..$E1: begin Opcode := RESERVED; end; $E2: begin Opcode := 'fnclex'; end; $E3: begin Opcode := 'fninit'; end; $E4: begin Opcode := RESERVED; end; else Opcode := INVALID; end; end; procedure DoDC; const OPC: array[0..7] of String = ('fadd', 'fmul', 'fcom', 'fcomp', 'fsub', 'fsubr', 'fdiv', 'fdivr'); OPCx: array[0..7] of String = ('fadd', 'fmul', '', '', 'fsubr', 'fsub', 'fdivr', 'fdiv'); begin case ModRM of $00..$BF: begin Opcode := OPC[Index]; AddMem64; end; $C0..$CF, $E0..$FF: begin Opcode := OPCx[Index]; AddRegN; AddReg0; end; else Opcode := RESERVED; end; end; procedure DoDD; const OPC: array[0..7] of String = ('fld', 'fisttp', 'fst', 'fstp', 'frstor', '', 'fnsave', 'fnstsw'); OPCx: array[0..7] of String = ('ffree', '', 'fst', 'fstp', '', 'fucomp', '', ''); begin case ModRM of $00..$BF: begin case Index of 0..3: begin Opcode := OPC[Index]; AddMem64; end; 4, 6: begin Opcode := OPC[Index]; AddMem98_108Env; end; 5: Opcode := INVALID; 7: begin Opcode := OPC[Index]; AddMem16; end; end; end; $C0..$C7, $D0..$DF, $E8..$EF: begin Opcode := OPCx[Index]; AddRegN; end; $E0..$E7: begin Opcode := OPCx[Index]; AddRegN; AddReg0; end; $C8..$CF: Opcode := RESERVED; else Opcode := INVALID; end end; procedure DoDE; const OPC: array[0..7] of String = ('fiadd', 'fimull', 'ficom', 'ficomp', 'fisub', 'fisubr', 'fidiv', 'fidivr'); OPCx: array[0..7] of String = ('faddp', 'fmullp', '', '', 'fsubrp', 'fsubp', 'fdivrp', 'fdivp'); begin case ModRM of $00..$BF: begin Opcode := OPC[Index]; AddMem16; end; $C0..$CF, $E0..$FF: begin Opcode := OPCx[Index]; AddRegN; AddReg0; end; $D9: begin Opcode := 'fcompp'; end; $D0..$D7: Opcode := RESERVED; else Opcode := INVALID; end; end; procedure DoDF; const OPC: array[0..7] of String = ('fild', 'fisttp', 'fist', 'fistp', 'fbld', 'fild', 'fbstp', 'fistp'); begin case ModRM of $00..$BF: begin case Index of 0..3: begin Opcode := OPC[Index]; AddMem16; end; 4, 6: begin Opcode := OPC[Index]; AddMem80; end; 5, 7: begin Opcode := OPC[Index]; AddMem64; end; end; end; $E0: begin Opcode := 'fnstsw'; AddOperand('ax', os16); end; $E8..$EF: begin Opcode := 'fucomip'; AddReg0; AddRegN; end; $F0..$F7: begin Opcode := 'fcomip'; AddReg0; AddRegN; end; $C0..$DF: Opcode := RESERVED; else Opcode := INVALID; end; end; begin Include(Flags, flagModRM); ModRM := Code[ModRMIdx]; Index := (ModRM shr 3) and $7; case Code[CodeIdx] of $D8: DoD8; $D9: DoD9; $DA: DoDA; $DB: DoDB; $DC: DoDC; $DD: DoDD; $DE: DoDE; $DF: DoDF; else Opcode := '!x87!'; end; end; procedure 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 operand for the 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, Operand[n].ByteCount); Inc(idx, Operand[n].ByteCount2); end; // now we can lookup the opcode case Code[CodeIdx + idx] of $0C: Opcode := 'pi2fw'; $0D: Opcode := 'pi2fd'; $1C: Opcode := 'pf2iw'; $1D: Opcode := 'pf2id'; $8A: Opcode := 'pfnacc'; $8E: Opcode := 'pfpnacc'; $90: Opcode := 'pfcmpge'; $94: Opcode := 'pfmin'; $96: Opcode := 'pfrcp'; $97: Opcode := 'pfrsqrt'; $9A: Opcode := 'pfsub'; $9E: Opcode := 'pfadd'; $A0: Opcode := 'pgcmpgt'; $A4: Opcode := 'pfmax'; $A6: Opcode := 'pfrcpit1'; $A7: Opcode := 'pfrsqit1'; $AA: Opcode := 'pfsubr'; $AE: Opcode := 'pfacc'; $B0: Opcode := 'pfcmpeq'; $B4: Opcode := 'pfmul'; $B6: Opcode := 'pfrcpit2'; $B7: Opcode := 'pmulhrw'; $BB: Opcode := 'pswapd'; $BF: Opcode := 'pavgusb'; else Opcode := '-3dnow-'; end; end; // Group procedure DoGroup1; const OPC: array[0..7] of String = ('add', 'or', 'adc', 'sbb', 'and', 'sub', 'xor', 'cmp'); var Index: Byte; begin Include(Flags, flagModRM); Index := (Code[ModRMIdx] shr 3) and 7; // group 1a if Code[CodeIdx] = $8F then begin if Index = 0 then begin Opcode := 'pop'; AddEv; end else Opcode := '**group1a**'; Exit; end; // Group 1 Opcode := OPC[Index]; case Code[CodeIdx] of $80: begin AddEb; AddIb; end; $81: begin AddEv; AddIz; end; $82: begin AddEb; AddIb; Opcode := Check32(Opcode); end; $83: begin AddEv; AddIb; end; else Opcode := '!group1!'; Exit; end; if (Index <> 7) then Opcode := CheckLock(Opcode); end; procedure DoGroup2; const OPC: array[0..7] of String = ('rol', 'ror', 'rcl', 'rcr', 'shl', 'shr', 'sal', 'sar'); var Index: Byte; begin Include(Flags, flagModRM); Index := (Code[ModRMIdx] shr 3) and 7; Opcode := OPC[Index]; case Code[CodeIdx] of $C0: begin AddEb; AddIb; end; $C1: begin AddEv; AddIb; end; $D0: begin AddEb; AddOperand('1', os8); end; $D1: begin AddEv; AddOperand('1', os8); end; $D2: begin AddEb; AddOperand('cl', os8); end; $D3: begin AddEv; AddOperand('cl', os8); end; else Opcode := '!group2!'; end; end; procedure DoGroup3; const OPC: array[0..7] of String = ('test', 'test', 'not', 'neg', 'mul', 'imul', 'div', 'idiv'); var Index: Byte; begin Include(Flags, flagModRM); Index := (Code[ModRMIdx] shr 3) and 7; Opcode := OPC[Index]; case Code[CodeIdx] of $F6: begin if (Index = 0) or (Index = 1) then begin AddEb; AddIb; end else begin AddEb; end; end; $F7: begin if (Index = 0) or (Index = 1) then begin AddEv; AddIz; end else begin AddEv; end; end; else Opcode := '!group3!'; Exit; end; if (Index = 2) or (Index = 3) then Opcode := CheckLock(Opcode); end; procedure DoGroup4; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $FE then begin Opcode := '!group4!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case Index of 0: Opcode := 'inc'; 1: Opcode := 'dec'; else Opcode := '**group4**'; Exit; end; AddEb; Opcode := CheckLock(Opcode); end; procedure DoGroup5; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $FF then begin Opcode := '!group5!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case Index of 0: begin AddEv; Opcode := CheckLock('inc'); end; 1: begin AddEv; Opcode := CheckLock('dec'); end; 2: begin AddEv; Opcode := 'call'; end; 3: begin AddMp; Opcode := 'call'; end; 4: begin AddEv; Opcode := 'jmp'; end; 5: begin AddMp; Opcode := 'jmp'; end; 6: begin AddEv; Opcode := 'push'; end; else Opcode := '**group5**'; Exit; end; end; procedure DoGroup6; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $00 then begin Opcode := '!group6!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case Index of 0: begin AddMw_Rv; Opcode := 'sldt'; end; 1: begin AddMw_Rv; Opcode := 'str'; end; 2: begin AddEw; Opcode := 'lldt'; end; 3: begin AddEw; Opcode := 'ltr'; end; 4: begin AddEw; Opcode := 'verr'; end; 5: begin AddEw; Opcode := 'verw'; end; else Opcode := '**group6**'; Exit; end; end; procedure DoGroup7; const RM3: array [0..7] of String = ('vmrun', 'vmmcall', 'vmload', 'vmsave', 'stgi', 'clgi', 'skinit', 'invlpga'); var Mode: Byte; Index: Byte; RM: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $01 then begin Opcode := '!group7!'; Exit; end; Mode := (Code[ModRMIdx] shr 6) and 3; Index := (Code[ModRMIdx] shr 3) and 7; RM := (Code[ModRMIdx] ) and 7; case Index of 0: begin AddMs; Opcode := 'sgdt'; end; 1: begin AddMs; Opcode := 'sidt'; end; 2: begin AddMs; Opcode := 'lgdt'; end; 3: begin if Mode = 3 then begin Opcode := RM3[RM]; end else begin AddMs; Opcode := 'lidt'; end; end; 4: begin AddMw_Rv; Opcode := 'smsw'; end; //5 : invalid 6: begin AddEw; Opcode := 'lmsw'; end; 7: begin if Mode = 3 then begin case RM of 0: Opcode := 'swapgs'; 1: Opcode := 'rdtscp'; else Opcode := '**group7**'; end; end else begin AddMb; Opcode := 'invlpg'; end; end; else Opcode := '**group7**'; Exit; end; end; procedure DoGroup8; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $BA then begin Opcode := '!group8!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; if Index < 4 then begin Opcode := '**group8**'; Exit; end; AddEv; AddIb; case Index of 4: Opcode := 'bt'; 5: Opcode := CheckLock('bts'); 6: Opcode := CheckLock('btr'); 7: Opcode := CheckLock('btc'); end; end; procedure DoGroup9; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $C7 then begin Opcode := '!group9!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; if Index = 1 then begin if OperandSize32 = os64 then begin Opcode := CheckLock('cmpxchg16b'); AddMdq; end else begin Opcode := CheckLock('cmpxchg8b'); AddMq; end; end else Opcode := '**group9**'; end; procedure DoGroup10; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $B9 then begin Opcode := '!group10!'; Exit; end; // whole goup is invalid ?? Opcode := '**group10**'; end; procedure DoGroup11; var Index: Byte; begin Include(Flags, flagModRM); Index := (Code[ModRMIdx] shr 3) and 7; if Index <> 0 then begin Opcode := '**group11**'; Exit; end; case Code[CodeIdx] of $C6: begin AddEb; AddIb; end; $C7: begin AddEv; AddIz; end; else Opcode := '!group5!'; Exit; end; Opcode := 'mov'; end; procedure DoGroup12; const OPC: array[0..7] of String = ('', '', 'psrlw', '', 'psraw', '', 'psllw', ''); var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $71 then begin Opcode := '!group12!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case DecodePrefix(OPC[Index], '', OPC[Index], '') of 0: begin AddPRq; AddIb; end; 2: begin AddVRdq; AddIb; end; else Opcode := '**group12**'; end; end; procedure DoGroup13; const OPC: array[0..7] of String = ('', '', 'psrld', '', 'psrad', '', 'pslld', ''); var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $72 then begin Opcode := '!group13!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case DecodePrefix(OPC[Index], '', OPC[Index], '') of 0: begin AddPRq; AddIb; end; 2: begin AddVRdq; AddIb; end; else Opcode := '**group13**'; end; end; procedure DoGroup14; const OPC: array[0..7] of String = ('', '', 'psrlq', 'psrldq', '', '', 'psllq', 'psrldq'); var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $73 then begin Opcode := '!group14!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case DecodePrefix(OPC[Index], '', OPC[Index], '') of 0: begin if (Index = 3) or (Index = 7) then Opcode := '**group14**' else begin AddPRq; AddIb; end; end; 2: begin AddVRdq; AddIb; end; else Opcode := '**group14**'; end; end; procedure DoGroup15; var Index: Byte; Mode: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $AE then begin Opcode := '!group15!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; if (Flags * [preOpr, preRep, preRepNE] <> []) or (Index = 4) then begin Opcode := '**group15**'; Exit; end; Mode := (Code[ModRMIdx] shr 6) and 3; case Index of 0: begin Opcode := 'fxsave'; AddM; end; 1: begin Opcode := 'fxrstor'; AddM; end; 2: begin Opcode := 'ldmxcsr'; AddMd; end; 3: begin Opcode := 'stmxcsr'; AddMd; end; 5: Opcode := 'lfence'; 6: Opcode := 'mfence'; 7: if Mode = 3 then Opcode := 'lfence' else begin Opcode := 'clflush'; AddMb; end; end; end; procedure DoGroup16; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $18 then begin Opcode := '!group16!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; end; procedure DoGroupP; var Index: Byte; begin Include(Flags, flagModRM); if Code[CodeIdx] <> $0D then begin Opcode := '!groupp!'; Exit; end; Index := (Code[ModRMIdx] shr 3) and 7; case Index of 0: Opcode := 'prefetch exclusive'; 1,3: Opcode := 'prefetch modified'; else Opcode := '--prefetch--' end; end; //--- procedure Do2ByteOpcode; const INVALID = '**2byte**'; const OPR_6x: array[0..$F] of String = ( 'punpcklbw', 'punpcklwd', 'punpcklqd', 'packsswb', 'pcmpgtb', 'pcmpgtw', 'pcmpgtd', 'packuswb', 'punpkhbw', 'punpkhwd', 'punpkhdq', 'packssdw', 'punpcklqdq', 'punpckhqdq', '', '' ); OPR_Dx: array[0..$F] of String = ( '', 'psrlw', 'psrld', 'psrlq', 'paddq', 'pmullw', '', '', 'psubusb', 'psubusw', 'pminub', 'pand', 'paddusb', 'paddusw', 'pmaxub', 'pandn' ); OPR_Ex: array[0..$F] of String = ( 'pavgb', 'psraw', 'psrad', 'pavgw', 'pmulhuw', 'pmulhw', '', '', 'psubsb', 'psubsw', 'pminsw', 'por', 'paddsb', 'paddsw', 'pmaxsw', 'pxor' ); OPR_Fx: array[0..$F] of String = ( '', 'psllw', 'pslld', 'psllq', 'pmuludq', 'pmaddwd', 'psadbw', '', 'psubb', 'psubw', 'psubd', 'psubq', 'paddb', 'paddw', 'paddd', '' ); var idx: Integer; begin Inc(CodeIdx); Inc(ModRMIdx); case Code[CodeIdx] of $00: begin DoGroup6; end; $01: begin DoGroup7; end; $02: begin Opcode := 'lar'; AddGv; AddEw; end; $03: begin Opcode := 'lsl'; AddGv; AddEw; end; // $04: invalid $05: begin Opcode := 'syscall'; end; $06: begin Opcode := 'clts'; end; $07: begin Opcode := 'sysret'; end; $08: begin Opcode := 'invd'; end; $09: begin Opcode := 'wbinvd'; end; // $0A: invalid $0B: begin Opcode := 'ud2'; end; // $0C: invalid $0D: begin DoGroupP; end; $0E: begin Opcode := 'femms'; end; $0F: begin Do3DNow; end; //--- $10: begin case DecodePrefix('movups', 'movss', 'movupd', 'movsd') of 0: begin AddVps; AddWps; end; 1: begin AddVdq_ss; AddWss; end; 2: begin AddVpd; AddWpd; end; 3: begin AddVdq_sd; AddWsd; end; end; end; $11: begin case DecodePrefix('movups', 'movss', 'movupd', 'movsd') of 0: begin AddWps; AddVps; end; 1: begin AddWss; AddVss; end; 2: begin AddWpd; AddVpd; end; 3: begin AddWsd; AddVsd; end; end; end; $12: begin case DecodePrefix('movhlps', 'movsldup', 'movlpd', 'movddup') of 0: begin // Opcode differs on type found // it is specified as Mq or VRq // So when getting Wq, we Add both and know the type AddVps; AddWq; if ofMemory in Operand[2].Flags then Opcode := 'movlps'; end; 1: begin AddVps; AddWps; end; 2: begin AddVsd; AddMq; end; 3: begin AddVpd; AddWsd; end; end; end; $13: begin case DecodePrefix('movlps', '', 'movlpd', '') of 0: begin AddMq; AddVps; end; 2: begin AddMq; AddVsd; end; end; end; $14: begin case DecodePrefix('unpcklps', '', 'unpcklpd', '') of 0: begin AddVps; AddWq; end; 2: begin AddVpd; AddWq; end; else Opcode := INVALID; end; end; $15: begin case DecodePrefix('unpckhps', '', 'unpckhpd', '') of 0: begin AddVps; AddWq; end; 2: begin AddVpd; AddWq; end; else Opcode := INVALID; end; end; $16: begin case DecodePrefix('movlhps', 'movshdup', 'movhpd', '') of 0: begin // Opcode differs on type found // it is specified as Mq or VRq // So when getting Wq, we Add both and know the type AddVps; AddWq; if ofMemory in Operand[2].Flags then Opcode := 'movhps'; end; 1: begin AddVps; AddWps; end; 2: begin AddVsd; AddMq; end; else Opcode := INVALID; end; end; $17: begin case DecodePrefix('movhps', '', 'movhpd', '') of 0: begin AddMq; AddVps; end; 2: begin AddMq; AddVsd; end; else Opcode := INVALID; end; end; $18: begin DoGroup16; end; $19..$1F: begin Include(Flags, flagModRM); Opcode := 'nop'; end; //--- $20: begin Opcode := 'mov'; AddRd_q; AddCd_q; end; $21: begin Opcode := 'mov'; AddRd_q; AddDd_q; end; $22: begin Opcode := 'mov'; AddCd_q; AddRd_q; end; $23: begin Opcode := 'mov'; AddDd_q; AddRd_q; end; // $24..$27: invalid $28: begin case DecodePrefix('movaps', '', 'movapd', '') of 0: begin AddVps; AddWps; end; 2: begin AddVpd; AddWpd; end; else Opcode := INVALID; end; end; $29: begin case DecodePrefix('movaps', '', 'movapd', '') of 0: begin AddWps; AddVps; end; 2: begin AddWpd; AddVpd; end; else Opcode := INVALID; end; end; $2A: begin case DecodePrefix('cvtpi2ps', 'cvtsi2ss', 'cvtpi2pd', 'cvtsi2sd') of 0: begin AddVps; AddQq; end; 1: begin AddVss; AddEd_q; end; 2: begin AddVpd; AddQq; end; 3: begin AddVsd; AddEd_q; end; end; end; $2B: begin case DecodePrefix('movntps', '', 'movntpd', '') of 0: begin AddMdq; AddVps; end; 2: begin AddMdq; AddVpd; end; else Opcode := INVALID; end; end; $2C: begin case DecodePrefix('cvttps2pi', 'cvttss2pi', 'cvttpd2pi', 'cvttsd2pi') of 0: begin AddPq; AddWps; end; 1: begin AddGd_q; AddWss; end; 2: begin AddPq; AddWpd; end; 3: begin AddGd_q; AddWsd; end; end; end; $2D: begin case DecodePrefix('cvtps2pi', 'cvtss2pi', 'cvtpd2pi', 'cvtsd2pi') of 0: begin AddPq; AddWps; end; 1: begin AddGd_q; AddWss; end; 2: begin AddPq; AddWpd; end; 3: begin AddGd_q; AddWsd; end; end; end; $2E: begin case DecodePrefix('ucomiss', '', 'ucomissd', '') of 0: begin AddVss; AddWss; end; 2: begin AddVsd; AddWsd; end; else Opcode := INVALID; end; end; $2F: begin case DecodePrefix('comiss', '', 'comissd', '') of 0: begin AddVss; AddWss; end; 2: begin AddVsd; AddWsd; end; else Opcode := INVALID; end; end; //--- $30: begin Opcode := 'wrmsr'; end; $31: begin Opcode := 'rdtsc'; end; $32: begin Opcode := 'rdmsr'; end; $33: begin Opcode := 'rdpmc'; end; $34: begin Opcode := '**sysenter**'; end; $35: begin Opcode := '**sysexit**'; end; // $36..$3F: invalid //--- $40..$4F: begin Opcode := 'cmov' + StdCond(Code[CodeIdx]); AddGv; AddEv; end; //--- $50: begin case DecodePrefix('movmskps', '', 'movmskpd', '') of 0: begin AddGd; AddVRps; end; 2: begin AddGd; AddVRpd; end; else Opcode := INVALID; end; end; $51, $58..$59, $5C..$5F: begin case Code[CodeIdx] of $51: Idx := DecodePrefix('sqrtps', 'sqrtss', 'sqrtpd', 'sqrtsd'); $58: Idx := DecodePrefix('addps', 'addss', 'addpd', 'addsd'); $59: Idx := DecodePrefix('mulps', 'mulss', 'mulpd', 'mulsd'); $5C: Idx := DecodePrefix('subps', 'subss', 'subpd', 'subsd'); $5D: Idx := DecodePrefix('minps', 'minss', 'minpd', 'minsd'); $5E: Idx := DecodePrefix('divps', 'divss', 'divpd', 'divsd'); $5F: Idx := DecodePrefix('maxps', 'maxss', 'maxpd', 'maxsd'); else Idx := -1; end; case Idx of 0: begin AddVps; AddWps; end; 1: begin AddVss; AddWss; end; 2: begin AddVpd; AddWpd; end; 3: begin AddVsd; AddWsd; end; else Opcode := INVALID; end; end; $52: begin case DecodePrefix('rsqrtps', 'rsqrtss', '', '') of 0: begin AddVps; AddWps; end; 1: begin AddVss; AddWss; end; else Opcode := INVALID; end; end; $53: begin case DecodePrefix('rcpps', 'rcpss', '', '') of 0: begin AddVps; AddWps; end; 1: begin AddVss; AddWss; end; else Opcode := INVALID; end; end; $54: begin case DecodePrefix('andps', '', 'andpd', '') of 0: begin AddVps; AddWps; end; 2: begin AddVpd; AddWpd; end; else Opcode := INVALID; end; end; $55: begin case DecodePrefix('andnps', '', 'andnpd', '') of 0: begin AddVps; AddWps; end; 2: begin AddVpd; AddWpd; end; else Opcode := INVALID; end; end; $56: begin case DecodePrefix('orps', '', 'orpd', '') of 0: begin AddVps; AddWps; end; 2: begin AddVpd; AddWpd; end; else Opcode := INVALID; end; end; $57: begin case DecodePrefix('xorps', '', 'xorpd', '') of 0: begin AddVps; AddWps; end; 2: begin AddVpd; AddWpd; end; else Opcode := INVALID; end; end; // $58..$59: see $51 $5A: begin case DecodePrefix('cvtps2pd', 'cvtss2sd', 'cvtpd2ps', 'cvtsd2ss') of 0: begin AddVpd; AddWps; end; 1: begin AddVsd; AddWss; end; 2: begin AddVps; AddWpd; end; 3: begin AddVss; AddWsd; end; end; end; $5B: begin case DecodePrefix('cvtdq2ps', 'cvttps2dq', 'cvtps2dq', '') of 0: begin AddVps; AddWdq; end; 1: begin AddVdq; AddWps; end; 2: begin AddVdq; AddWps; end; else Opcode := INVALID; end; end; // $5C..$5F: see $51 //--- $60..$6D: begin idx := Code[CodeIdx] and $F; idx := DecodePrefix(OPR_6x[idx], '', OPR_6x[idx], ''); if (idx = 0) and (Code[CodeIdx] in [$6C, $6D]) then idx := -1; case Idx of 0: begin AddPq; AddQd; end; 2: begin AddVdq; if Code[CodeIdx] = $6B then AddWdq else AddWq; end; else Opcode := INVALID; end; end; $6E: begin case DecodePrefix('movd', '', 'movd', '') of 0: begin AddPq; AddEd_q; end; 2: begin AddVdq; AddEd_q; end; else Opcode := INVALID; end; end; $6F: begin case DecodePrefix('movq', 'movdqu', 'movdqa', '') of 0: begin AddPq; AddQq; end; 1: begin AddVdq; AddWdq; end; 2: begin AddVdq; AddWdq; end; else Opcode := INVALID; end; end; //--- $70: begin case DecodePrefix('pshufw', 'pshufhw', 'pshufd', 'pshuflw') of 0: begin AddPq; AddQq; AddIb; end; 1: begin AddVq; AddWq; AddIb; end; 2: begin AddVdq; AddWdq; AddIb; end; 3: begin AddVq; AddWq; AddIb; end; end; end; $71: begin if Flags * [preRep, preRepNE] = [] then DoGroup12 else Opcode := INVALID; end; $72: begin if Flags * [preRep, preRepNE] = [] then DoGroup13 else Opcode := INVALID; end; $73: begin if Flags * [preRep, preRepNE] = [] then DoGroup14 else Opcode := INVALID; end; $74: begin case DecodePrefix('pcmpeqb', '', 'pcmpeqb', '') of 0: begin AddPq; AddQq; end; 2: begin AddVdq; AddWdq; end; else Opcode := INVALID; end; end; $75: begin case DecodePrefix('pcmpeqw', '', 'pcmpeqw', '') of 0: begin AddPq; AddQq; end; 2: begin AddVdq; AddWdq; end; else Opcode := INVALID; end; end; $76: begin case DecodePrefix('pcmpeqd', '', 'pcmpeqd', '') of 0: begin AddPq; AddQq; end; 2: begin AddVdq; AddWdq; end; else Opcode := INVALID; end; end; $77: begin if Flags * [preRep, preRepNE, preOpr] = [] then Opcode := 'emms' else Opcode := INVALID; end; // $78..$7B: invalid $7C: begin case DecodePrefix('', '', 'haddpd', 'haddps') of 2: begin AddVpd; AddWpd; end; 3: begin AddVps; AddWps; end; else Opcode := INVALID; end; end; $7D: begin case DecodePrefix('', '', 'hsubpd', 'hsubps') of 2: begin AddVpd; AddWpd; end; 3: begin AddVps; AddWps; end; else Opcode := INVALID; end; end; $7E: begin case DecodePrefix('movd', 'movq', 'movd', '') of 0: begin AddEd_q; AddPd_q; end; 1: begin AddVq; AddWq; end; 2: begin AddEd_q; AddVd_q; end; else Opcode := INVALID; end; end; $7F: begin case DecodePrefix('movq', 'movdqu', 'movdqa', '') of 0: begin AddQq; AddPq; end; 1: begin AddWdq; AddVdq; end; 2: begin AddWdq; AddVdq; end; else Opcode := INVALID; end; end; //--- $80..$8F: begin Opcode := 'j' + StdCond(Code[CodeIdx]); AddJz; end; //--- $90..$9F: begin Opcode := 'set' + StdCond(Code[CodeIdx]); AddEb; end; //--- $A0: begin Opcode := 'push'; AddOperand('fs'); end; $A1: begin Opcode := 'pop'; AddOperand('fs'); end; $A2: begin Opcode := 'cpuid'; end; $A3: begin Opcode := 'bt'; AddEv; AddGv; end; $A4: begin Opcode := 'shld'; AddEv; AddGv; AddIb; end; $A5: begin Opcode := 'shld'; AddEv; AddGv; AddOperand('cl'); end; // $A6..$A7: invalid $A8: begin Opcode := 'push'; AddOperand('gs'); end; $A9: begin Opcode := 'pop'; AddOperand('gs'); end; $AA: begin Opcode := 'rsm'; end; $AB: begin Opcode := 'bts'; AddEv; AddGv; end; $AC: begin Opcode := 'shrd'; AddEv; AddGv; AddIb; end; $AD: begin Opcode := 'shld'; AddEv; AddGv; AddOperand('cl'); end; $AE: begin DoGroup15; end; $AF: begin Opcode := 'imul'; AddGv; AddEv; end; //--- $B0: begin AddEb; AddGb; Opcode := CheckLock('cmpxchg'); end; $B1: begin AddEv; AddGv; Opcode := CheckLock('cmpxchg'); end; $B2: begin Opcode := 'lss'; AddGz; AddMp; end; $B3: begin Opcode := 'btr'; AddEv; AddGv; end; $B4: begin Opcode := 'lfs'; AddGz; AddMp; end; $B5: begin Opcode := 'lgs'; AddGz; AddMp; end; $B6: begin Opcode := 'movzx'; AddGv; AddEb; end; $B7: begin Opcode := 'movzx'; AddGv; AddEw; end; // $B8: invalid $B9: begin DoGroup10; end; $BA: begin DoGroup8; end; $BB: begin Opcode := 'btc'; AddEv; AddGv; end; $BC: begin Opcode := 'bsf'; AddGv; AddEv; end; $BD: begin Opcode := 'bsr'; AddGv; AddEv; end; $BE: begin Opcode := 'movsx'; AddGv; AddEb; end; $BF: begin Opcode := 'movsx'; AddGv; AddEw; end; //--- $C0: begin AddEb; AddGb; Opcode := CheckLock('xadd'); end; $C1: begin AddEv; AddGv; Opcode := CheckLock('xadd'); end; $C2: begin case DecodePrefix('cmpps', 'cmpss', 'cmppd', 'cmpsd') of 0: begin AddVps; AddWps; AddIb end; 1: begin AddVss; AddWss; AddIb end; 2: begin AddVpd; AddWpd; AddIb end; 3: begin AddVsd; AddWsd; AddIb end; end; end; $C3: begin if Flags * [preRep, preRepNE, preOpr] = [] then begin Opcode := 'movnti'; AddMd_q; AddGd_q; end else Opcode := INVALID; end; $C4: begin case DecodePrefix('pinsrw', '', 'pinsrw', '') of 0: begin AddPq; AddEw; AddIb end; 2: begin AddVdq; AddEw; AddIb end; else Opcode := INVALID; end; end; $C5: begin case DecodePrefix('pextrw', '', 'pextrw', '') of 0: begin AddGd; AddPRq; AddIb end; 2: begin AddGd; AddVRdq; AddIb end; else Opcode := INVALID; end; end; $C6: begin case DecodePrefix('shufps', '', 'shufpd', '') of 0: begin AddVps; AddWps; AddIb end; 2: begin AddVpd; AddWpd; AddIb end; else Opcode := INVALID; end; end; $C7: begin DoGroup9; end; $C8..$CF: begin Opcode := 'bswp'; AddStdReg(Code[CodeIdx]); end; //--- $D0: begin case DecodePrefix('', '', 'addsubpd', 'addsubps') of 2: begin AddVpd; AddWpd; end; 3: begin AddVps; AddWps; end; else Opcode := INVALID; end; end; $D1..$D5, $D8..$DF: begin idx := Code[CodeIdx] and $F; idx := DecodePrefix(OPR_Dx[idx], '', OPR_Dx[idx], ''); case Idx of 0: begin AddPq; AddQq; end; 2: begin AddVdq; AddWdq; end; else Opcode := INVALID; end; end; $D6: begin case DecodePrefix('', 'movq2dq', 'movq', 'movdq2q') of 1: begin AddVdq; AddPRq; end; 2: begin AddWq; AddVq; end; 3: begin AddPq; AddVRq; end; else Opcode := INVALID; end; end; $D7: begin case DecodePrefix('pmovmskb', '', 'pmovmskb', '') of 0: begin AddGd; AddPRq; end; 2: begin AddGd; AddVRdq; end; else Opcode := INVALID; end; end; // $D8..$DF: see $D1 //--- $E0..$E5, $E8..$EF: begin idx := Code[CodeIdx] and $F; idx := DecodePrefix(OPR_Ex[idx], '', OPR_Ex[idx], ''); case Idx of 0: begin AddPq; AddQq; end; 2: begin AddVdq; AddWdq; end; else Opcode := INVALID; end; end; $E6: begin case DecodePrefix('', 'cvtdq2pd', 'cvttpd2dq', 'cvtpd2dq') of 1: begin AddVpd; AddWq; end; 2: begin AddVq; AddWpd; end; 3: begin AddVq; AddWpd; end; else Opcode := INVALID; end; end; $E7: begin case DecodePrefix('movntq', '', 'movntdqu', '') of 0: begin AddMq; AddPq; end; 2: begin AddMdq; AddVdq; end; else Opcode := INVALID; end; end; // $E8..$EF: see $E0 $F0: begin if preRepNE in Flags then begin Opcode := 'lddqu'; AddVpd; AddMdq; end else Opcode := INVALID; end; $F1..$F6, $F8..$FE: begin idx := Code[CodeIdx] and $F; idx := DecodePrefix(OPR_Fx[idx], '', OPR_Fx[idx], ''); case Idx of 0: begin AddPq; AddQq; end; 2: begin AddVdq; AddWdq; end; else Opcode := INVALID; end; end; $F7: begin case DecodePrefix('maskmovq', '', 'maskmovdqu', '') of 0: begin AddPq; AddPRq; end; 2: begin AddVdq; AddVRdq; end; else Opcode := INVALID; end; end; // $F8..$FE: see $F1 // $FF: invalid else Opcode := INVALID; end; end; procedure DoDisassemble; begin repeat ModRMIdx := CodeIdx + 1; case Code[CodeIdx] of $00..$05: begin AddStdOperands(Code[CodeIdx]); Opcode := CheckLock('add'); end; $06: begin Opcode := Check32('push'); AddOperand('es'); end; $07: begin Opcode := Check32('pop'); AddOperand('es'); end; $08..$0D: begin AddStdOperands(Code[CodeIdx]); Opcode := CheckLock('or'); end; $0E: begin Opcode := Check32('push'); AddOperand('cs'); end; $0F: begin Do2ByteOpcode; end; //--- $10..$15: begin AddStdOperands(Code[CodeIdx]); Opcode := CheckLock('adc'); end; $16: begin Opcode := Check32('push'); AddOperand('ss'); end; $17: begin Opcode := Check32('pop'); AddOperand('ss'); end; $18..$1D: begin AddStdOperands(Code[CodeIdx]); Opcode := CheckLock('sbb'); end; $1E: begin Opcode := Check32('push'); AddOperand('ds'); end; $1F: begin Opcode := Check32('pop'); AddOperand('ds'); end; //--- $20..$25: begin AddStdOperands(Code[CodeIdx]); Opcode := CheckLock('and'); end; $26: begin Segment := Segment + Ignore64('es:'); end; $27: begin Opcode := Check32('daa'); end; $28..$2D: begin AddStdOperands(Code[CodeIdx]); Opcode := CheckLock('sub'); end; $2E: begin Segment := Segment + Ignore64('cs:'); end; $2F: begin Opcode := Check32('das'); end; //--- $30..$35: begin AddStdOperands(Code[CodeIdx]); Opcode := CheckLock('xor'); end; $36: begin Segment := Segment + Ignore64('ss:'); end; $37: begin Opcode := Check32('aaa'); end; $38..$3D: begin Opcode := 'cmp'; AddStdOperands(Code[CodeIdx]); end; $3E: begin Segment := Segment + Ignore64('ds:'); end; $3F: begin Opcode := Check32('aas'); end; //--- $40..$4F: begin if A64Bit then begin if (Code[CodeIdx] and 1) <> 0 then Include(Flags, rexB); if (Code[CodeIdx] and 2) <> 0 then Include(Flags, rexX); if (Code[CodeIdx] and 4) <> 0 then Include(Flags, rexR); if (Code[CodeIdx] and 8) <> 0 then Include(Flags, rexW); Include(Flags, flagRex); end else begin AddStdReg(Code[CodeIdx]); if Code[CodeIdx] <= $47 then Opcode := CheckLock('inc') else Opcode := CheckLock('dec'); end; end; //--- $50..$57: begin Opcode := 'push'; AddStdReg(Code[CodeIdx]); end; $58..$5F: begin Opcode := 'pop'; AddStdReg(Code[CodeIdx]); end; //--- $60: begin if OperandSize32 = os16 then Opcode := Check32('pusha') else Opcode := Check32('pushad'); end; $61: begin if OperandSize32 = os16 then Opcode := Check32('popa') else Opcode := Check32('popad'); end; $62: begin Opcode := Check32('bound'); AddGv; AddMa; end; $63: begin if A64Bit then begin Opcode := ('movsxd'); AddGv; AddEd; end else begin Opcode := Check32('arpl'); AddEw; AddGw; end; end; $64: begin Segment := Segment + 'fs:'; end; $65: begin Segment := Segment + 'gs:'; end; $66: begin Include(FLags, preOpr); end; $67: begin Include(FLags, preAdr); end; $68: begin Opcode := 'push'; AddIz; end; $69: begin Opcode := 'imul'; AddGv; AddEv; AddIz; end; $6A: begin Opcode := 'push'; AddIb; end; $6B: begin Opcode := 'imul'; AddGv; AddEv; AddIb; end; $6C: begin Opcode := CheckRepeat('insb'); {$ifdef verbose_string_instructions} AddYb; AddOperand('dx', os16); {$endif} end; $6D: begin if OperandSize32 = os16 then Opcode := CheckRepeat('insw') else Opcode := CheckRepeat('insd'); {$ifdef verbose_string_instructions} AddYz; AddOperand('dx', os16); {$endif} end; $6E: begin Opcode := CheckRepeat('outsb'); {$ifdef verbose_string_instructions} AddOperand('dx', os16); AddXb; {$endif} end; $6F: begin if OperandSize32 = os16 then Opcode := CheckRepeat('outsw') else Opcode := CheckRepeat('outsd'); {$ifdef verbose_string_instructions} AddOperand('dx', os16); AddXz; {$endif} end; $70..$7F: begin Opcode := 'j' + StdCond(Code[CodeIdx]); AddJb; end; //--- $80..$83: begin DoGroup1; end; $84: begin Opcode := 'test'; AddEb; AddGb; end; $85: begin Opcode := 'test'; AddEv; AddGv; end; $86: begin AddEb; AddGb; Opcode := CheckLock('xchg'); end; $87: begin AddEv; AddGv; Opcode := CheckLock('xchg'); end; $88..$8B: begin Opcode := 'mov'; AddStdOperands(Code[CodeIdx]); end; $8C: begin Opcode := 'mov'; AddMw_Rv; AddSw; end; $8D: begin Opcode := 'lea'; AddGv; AddM; end; $8E: begin Opcode := 'mov'; AddSw; AddEw; end; $8F: begin DoGroup1; end; //--- $90..$97: begin if (Code[CodeIdx] = $90) and not (rexR in Flags) then Opcode := 'nop' else begin Opcode := 'xchg'; AddStdReg(Code[CodeIdx]); AddOperand(SizeReg32('ax')); end; end; $98: begin case OperandSize32 of os64: Opcode := 'cdqe'; os32: Opcode := 'cwde'; else Opcode := 'cbw'; end; end; $99: begin case OperandSize32 of os64: Opcode := 'cqo'; os32: Opcode := 'cqd'; else Opcode := 'cwd'; end; end; $9A: begin Opcode := Check32('call'); AddAp; end; $9B: begin Opcode := 'wait/fwait'; end; $9C: begin case OperandSize32 of os64: Opcode := 'pushfq'; os32: Opcode := 'pushfd'; else Opcode := 'pushf'; end; AddFv; end; $9D: begin case OperandSize32 of os64: Opcode := 'popfq'; os32: Opcode := 'popfd'; else Opcode := 'popf'; end; AddFv; end; $9E: begin Opcode := 'sahf'; end; $9F: begin Opcode := 'lahf'; end; //--- $A0: begin Opcode := 'mov'; AddOperand('al', os8); AddOb; end; $A1: begin Opcode := 'mov'; AddOperand(SizeReg32('ax')); AddOv; end; $A2: begin Opcode := 'mov'; AddOb; AddOperand('al', os8); end; $A3: begin Opcode := 'mov'; AddOv; AddOperand(SizeReg32('ax')); end; $A4: begin Opcode := CheckRepeat('movsb'); {$ifdef verbose_string_instructions} AddYb; AddXb; {$endif} end; $A5: begin case OperandSize32 of os64: Opcode := CheckRepeat('movsq'); os32: Opcode := CheckRepeat('movsd'); else Opcode := CheckRepeat('movsw'); end; {$ifdef verbose_string_instructions} AddYv; AddXv; {$endif} end; $A6: begin Opcode := CheckRepeatX('cmpsb'); {$ifdef verbose_string_instructions} AddXb; AddYb; {$endif} end; $A7: begin case OperandSize32 of os64: Opcode := CheckRepeatX('cmpsq'); os32: Opcode := CheckRepeatX('cmpsd'); else Opcode := CheckRepeatX('cmpsw'); end; {$ifdef verbose_string_instructions} AddYv; AddXv; {$endif} end; $A8: begin Opcode := 'test'; AddOperand('al', os8); AddIb; end; $A9: begin Opcode := 'test'; AddOperand(SizeReg32('ax')); AddIv; end; $AA: begin Opcode := CheckRepeat('stosb'); {$ifdef verbose_string_instructions} AddYb; AddOperand('al', os8); {$endif} end; $AB: begin case OperandSize32 of os64: Opcode := CheckRepeat('stosq'); os32: Opcode := CheckRepeat('stosd'); else Opcode := CheckRepeat('stosw'); end; {$ifdef verbose_string_instructions} AddYv; AddOperand(SizeReg32('ax')); {$endif} end; $AC: begin Opcode := CheckRepeat('lodsb'); {$ifdef verbose_string_instructions} AddOperand('al', os8); AddXb; {$endif} end; $AD: begin case OperandSize32 of os64: Opcode := CheckRepeat('lodsq'); os32: Opcode := CheckRepeat('lodsd'); else Opcode := CheckRepeat('lodsw'); end; {$ifdef verbose_string_instructions} AddOperand(SizeReg32('ax')); AddXv; {$endif} end; $AE: begin Opcode := CheckRepeatX('scasb'); {$ifdef verbose_string_instructions} AddOperand('al', os8); AddYb; {$endif} end; $AF: begin case OperandSize32 of os64: Opcode := CheckRepeatX('scasq'); os32: Opcode := CheckRepeatX('scasd'); else Opcode := CheckRepeatX('scasw'); end; {$ifdef verbose_string_instructions} AddOperand(SizeReg32('ax')); AddYv; {$endif} end; //--- $B0..$B7: begin Opcode := 'mov'; AddStdReg(Code[CodeIdx], reg8, rexR in Flags); AddIb; end; $B8..$BF: begin Opcode := 'mov'; AddStdReg(Code[CodeIdx]); AddIv; end; //--- $C0..$C1: begin DoGroup2; end; $C2: begin Opcode := 'ret'; AddIw; end; $C3: begin Opcode := 'ret'; end; $C4: begin Opcode := 'les'; AddGz; AddMp; end; $C5: begin Opcode := 'lds'; AddGz; AddMp; end; $C6..$C7: begin DoGroup11; end; $C8: begin Opcode := 'enter'; AddIw; AddIb; end; $C9: begin Opcode := 'leave'; end; $CA: begin Opcode := 'retf'; AddIw; end; $CB: begin Opcode := 'retf'; end; $CC: begin Opcode := 'int3'; end; $CD: begin Opcode := 'int'; AddIb; end; $CE: begin Opcode := Check32('int0'); end; $CF: begin case OperandSize32 of os64: Opcode := 'iretq'; os32: Opcode := 'iretd'; else Opcode := 'iret'; end; end; //--- $D0..$D3: begin DoGroup2; end; $D4: begin Opcode := Check32('aam'); end; $D5: begin Opcode := Check32('aad'); end; $D6: begin Opcode := Check32('salc'); end; $D7: begin Opcode := 'xlat'; end; $D8..$DF: begin DoX87; end; //--- $E0: begin Opcode := 'loopne'; AddJb; end; $E1: begin Opcode := 'loope'; AddJb; end; $E2: begin Opcode := 'loop'; AddJb; end; $E3: begin Opcode := 'jrcxz'; AddJb; end; $E4: begin Opcode := 'in'; AddOperand('al', os8); AddIb; end; $E5: begin Opcode := 'in'; AddOperand(SizeReg32('ax')); AddIb; end; $E6: begin Opcode := 'out'; AddIb; AddOperand('al', os8); end; $E7: begin Opcode := 'out'; AddIb; AddOperand(SizeReg32('ax')); end; $E8: begin Opcode := 'call'; AddJz; end; $E9: begin Opcode := 'jmp'; AddJz; end; $EA: begin Opcode := Check32('jmp'); AddAp; end; $EB: begin Opcode := 'jmp'; AddJb; end; $EC: begin Opcode := 'in'; AddOperand('al', os8); AddOperand('dx', os16); end; $ED: begin Opcode := 'in'; AddOperand(SizeReg32('ax')); AddOperand('dx', os16); end; $EE: begin Opcode := 'out'; AddOperand('dx', os16); AddOperand('al', os8); end; $EF: begin Opcode := 'out'; AddOperand('dx', os16); AddOperand(SizeReg32('ax')); end; $F0: begin Include(Flags, preLock); end; $F1: begin Opcode := 'int1'; end; $F2: begin Include(Flags, preRepNE); end; $F3: begin Include(Flags, preRep); end; $F4: begin Opcode := 'hlt'; end; $F5: begin Opcode := 'cmc'; end; $F6..$F7: begin DoGroup3; end; $F8: begin Opcode := 'clc'; end; $F9: begin Opcode := 'stc'; end; $FA: begin Opcode := 'cli'; end; $FB: begin Opcode := 'sti'; end; $FC: begin Opcode := 'cld'; end; $FD: begin Opcode := 'std'; end; $FE: begin DoGroup4; end; $FF: begin DoGroup5; end; else Opcode := HexValue(Code[CodeIdx], 1, []); end; Inc(CodeIdx); if CodeIdx > 16 // max instruction length then begin Log('Disassemble: instruction longer than 16 bytes'); Exit; end; until Opcode <> ''; end; const MEMPTR: array[TOperandSize] of string = ('byte ptr ', 'word ptr ', 'dword ptr ', 'qword ptr ', '', 'tbyte ptr ', '16byte ptr '); {$ifdef debug_OperandSize} OSTEXT: array[TOperandSize] of string = ('os8', 'os16', 'os32', 'os64', 'os48', 'os80', 'os128'); {$endif} var S, Soper: String; n: Integer; HasMem: Boolean; begin Code := AAddress; Segment := ''; Opcode := ''; Flags := []; CodeIdx := 0; OperIdx := 0; DoDisassemble; if flagModRM in Flags then Inc(CodeIdx); if flagSib in Flags then Inc(CodeIdx); Soper := ''; HasMem := False; for n := 1 to OperIdx do begin if Operand[n].ByteCount = 0 then S := Operand[n].Value else begin if Operand[n].ByteCount2 = 0 then S := Format(Operand[n].Value, [HexValue(Code[CodeIdx], Operand[n].ByteCount, Operand[n].FormatFlags)]) else S := Format(Operand[n].Value, [HexValue(Code[CodeIdx], Operand[n].ByteCount, Operand[n].FormatFlags), HexValue(Code[CodeIdx + Operand[n].ByteCount], Operand[n].ByteCount2, Operand[n].FormatFlags)]) end; if Soper <> '' then Soper := Soper + ','; if ofMemory in Operand[n].Flags then begin if (OperIdx = 1) // or (Operand[n].Size <> os32) or (Operand[1].Size <> Operand[2].Size) then Soper := Soper + MEMPTR[Operand[n].Size]; Soper := Soper + Segment + '[' + S + ']'; HasMem := True; end else Soper := Soper + S; Inc(CodeIdx, Operand[n].ByteCount); Inc(CodeIdx, Operand[n].ByteCount2); end; {$ifdef debug_OperandSize} Soper := Soper + ' | '; for n := 1 to OperIdx do begin Soper := Soper + ' ' + OSTEXT[Operand[n].Size]; end; {$endif} S := ''; if preLock in Flags then S := S + '**lock**'; if preRep in Flags then S := S + '?rep?'; if preRepNE in Flags then S := S + '?repne?'; S := S + Opcode; if not HasMem and (Segment <> '') then S := S + ' ?' + Segment + '?'; ACode := S + ' ' + Soper; // memory S := ''; for n := 0 to CodeIdx - 1 do begin S := S + HexStr(Code[n], 2); end; ACodeBytes := S; Inc(AAddress, CodeIdx); end; end.