📄 disasmx.pas
字号:
unit DisAsmX;
interface
uses
SysUtils, dcAssignInstrTable;
type
TAddress = PAnsiChar;
PAddress = ^TAddress;
TFlag = (fZero, fOverflow);
TArgumentType = (atNone, atRegv, atRefv, atImm);
TRegister = (rEax, rEcx, rEdx, rEbx, rEsp, rEbp, rEsi, rEdi);
TRegisterType = (rtLowByte, rtHighByte, rtLowWord, rtDWord);
TdaRef = record
MultiplyReg1: Integer;
ARegister1: TRegister;
MultiplyReg2: Integer;
ARegister2: TRegister;
Immidiate: TAddress;
ImmidiateAddress: TAddress;
end;
TArgument = record
ArgumentType: TArgumentType;
case TArgumentType of
atNone:
();
atRefv:
( Ref: TdaRef );
atRegv:
( Reg: TRegister );
atImm:
( ImmValue: Cardinal;
ImmAddress: TAddress);
end;
TLoRepPrefix = (lrpNone, lrpLock, lrpRepNE, lrpRep);
const
LowLoRepPrefix = lrpLock;
HighLoRepPrefix = lrpRep;
type
TSegmentPrefix = (spNone, spCS, spSS, spDS, spES, spFS, spGS);
const
LowSegPrefix = spCS;
HighSegPrefix = spGS;
type
TOpcInstr = record
LoRepPrefix: TLoRepPrefix;
SegPrefix: TSegmentPrefix;
AddressSizePrefix: Boolean;
OperandSizePrefix: Boolean;
Mnemonic: TMnemonic;
Arguments: array[1..3] of TArgument;
end;
EDisAsmError = class(Exception);
const
// Lock Rep prefixes
LockPrefix = #$F0;
RepNEPrefix = #$F2;
RepPrefix = #$F3;
LoRepPrefixes: array[LowLoRepPrefix .. HighLoRepPrefix] of AnsiChar =
(LockPrefix, RepNEPrefix, RepPrefix);
// Segment prefixes
CSPrefix = #$2E;
SSPrefix = #$36;
DSPrefix = #$3E;
ESPrefix = #$26;
FSPrefix = #$64;
GSPrefix = #$65;
SegPrefixes: array[LowSegPrefix .. HighSegPrefix] of AnsiChar =
(CSPrefix, SSPrefix, dsPrefix, esPrefix, fsPrefix, gsPrefix);
// Operand size prefix
OperandSizePrefix = #$66;
// Address size prefix
AddressSizePrefix = #$67;
const
modrmReg = $38; // Reg part of the ModRM byte, ??XXX???
modrmMod = $C0; // Mod part of the ModRM byte, XX??????
modrmRM = $07; // RM part of the ModRM byte, ?????XXX
resourcestring
SInvalidInstructionError = 'Invalid instruction opcode at %p';
SNotYetSupported = 'This opcode is not yet supported';
SErrorInCode = 'This error shouldn''t occur';
function GetInstruction(Address: TAddress; var Size: Integer): TOpcInstr;
implementation
// Reads the instruction at Address and return the Size and
function GetInstruction(Address: TAddress; var Size: Integer): TOpcInstr;
var
Instr: TOpcInstr absolute Result;
procedure CheckPrefixes;
var
NotChanged: Boolean;
LoRepPrefix: TLoRepPrefix;
SegPrefix: TSegmentPrefix;
begin
repeat
NotChanged := True;
// Check LoRepPrefix.
for LoRepPrefix := LowLoRepPrefix to HighLoRepPrefix do
if Address[Size] = LoRepPrefixes[LoRepPrefix] then
begin
// Prefix may not already been set.
if Instr.LoRepPrefix <> lrpNone then
raise EDisAsmError.CreateFmt(SInvalidInstructionError, [Pointer(Address)]);
// Set the vars.
Instr.LoRepPrefix := LoRepPrefix;
NotChanged := False;
Size := Size + 1;
end;
// Check SegPrefix.
for SegPrefix := LowSegPrefix to HighSegPrefix do
if Address[Size] = SegPrefixes[SegPrefix] then
begin
// Prefix may not already been set.
if Instr.SegPrefix <> spNone then
raise EDisAsmError.CreateFmt(SInvalidInstructionError, [Pointer(Address)]);
// Set the vars.
Instr.SegPrefix := SegPrefix;
NotChanged := False;
Size := Size + 1;
end;
// Check Operand Size prefix.
if Address[Size] = OperandSizePrefix then
begin
// Prefix may not already been set.
if Instr.OperandSizePrefix then
raise EDisAsmError.CreateFmt(SInvalidInstructionError, [Pointer(Address)]);
// Set the vars.
Instr.OperandSizePrefix := True;
NotChanged := False;
Size := Size + 1;
end;
// Check Address Size prefix
if Address[Size] = AddressSizePrefix then
begin
// Prefix may not already been set.
if Instr.AddressSizePrefix then
raise EDisAsmError.CreateFmt(SInvalidInstructionError, [Pointer(Address)]);
// Set the vars.
Instr.AddressSizePrefix := True;
NotChanged := False;
Size := Size + 1;
end;
until NotChanged;
end; // End CheckPrefixes
// Only read the ModRM byte the first time it is asked.
// After that return the previous read ModRM byte
var
XHasModRM: Boolean;
XModRM: Byte;
function ReadByte: Byte;
begin
Result := Byte(Address[Size]);
Inc(Size, 1);
end;
function ModRM: Byte;
begin
if not XHasModRM then
begin
XModRM := ReadByte;
XHasModRM := True;
end;
Result := XModRM;
end;
var
Opc: TOpcode;
I: Integer;
procedure GetEffectiveAddress(const Arg: TArgumentOpcType);
var
RM: Byte;
AMod: Byte;
const
RegArgType: array[TArgumentOpcType] of TArgumentType =
(atNone, atRegv, atNone, atNone, atNone, atNone);
begin
RM := ModRM and modrmRM;
AMod := ModRm and modrmMod shr 6;
if AMod = 3 then
begin
// Effective address is a register.
Instr.Arguments[I].ArgumentType := RegArgType[Arg];
Instr.Arguments[I].Reg := TRegister(RM);
end
else
begin
// Effective address is not an register.
raise EDisAsmError.Create(SNotYetSupported);
end;
end; // End GetEffectiveAddress.
const
OpcodeRegs: array[TArgumentOpcType] of TRegister =
(rEax, rEax, rEax, rEax, {aotRegEAXv} rEax, {aotRegEBPv} rEbp);
begin
Size := 0;
FillChar(Instr, SizeOf(TOpcInstr), 0);
XHasModRM := False;
CheckPrefixes;
// Get the opcode information.
Opc := OneByteOpcodes[AnsiChar(ReadByte)];
Instr.Mnemonic := Opc.M;
// Get the Mnemonic.
for I := 1 to 3 do
case Opc.A[I] of
aotNone: ;
aotModRMRMv: GetEffectiveAddress(Opc.A[I]);
aotModRMRegv:
begin
Instr.Arguments[I].ArgumentType := atRegv;
Instr.Arguments[I].Reg := TRegister((ModRM and ModRMReg) div 8);
end;
aotImmb:
begin
Instr.Arguments[I].ArgumentType := atImm;
Instr.Arguments[I].ImmAddress := Address + Size;
Instr.Arguments[I].ImmValue := Cardinal(ReadByte);
end;
aotRegEAXv, aotRegEBPv:
begin
Instr.Arguments[I].ArgumentType := atRegv;
Instr.Arguments[I].Reg := OpcodeRegs[Opc.A[I]];
end;
else
raise EDisAsmError.Create(SErrorInCode);
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -