mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-02 06:03:44 +02:00
3101 lines
76 KiB
ObjectPascal
3101 lines
76 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., 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;
|
|
if Index=0 then ;
|
|
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.
|