cheat-engine/Cheat Engine/disassemblerarm.pas

2138 lines
53 KiB
ObjectPascal
Executable file

unit DisassemblerArm;
{$mode objfpc}{$H+}
interface
{$ifdef JNI}
uses unixporthelper, classes, sysutils, NewKernelHandler, LastDisassembleData, DisassemblerThumb;
{$endif}
{$ifdef windows}
uses
windows, Classes, SysUtils{$ifndef ARMDEV}, newkernelhandler, cefuncproc{$endif},
LastDisassembleData, DisassemblerThumb;
{$endif}
{$ifdef darwin}
uses macport, classes,SysUtils, newkernelhandler, cefuncproc,LastDisassembleData, DisassemblerThumb;
{$endif}
const ArmConditions: array [0..15] of string=('EQ','NE','CS', 'CC', 'MI', 'PL', 'VS', 'VC', 'HI', 'LS', 'GE', 'LT', 'GT', 'LE', '','NV');
const DataProcessingOpcodes: array [0..15] of string=('AND','EOR','SUB', 'RSB', 'ADD', 'ADC', 'SBC', 'RSC', 'TST', 'TEQ', 'CMP', 'CMN', 'ORR', 'MOV', 'BIC','MVN');
const ArmRegisters : array [0..15] of string= ('R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','FP', 'IP', 'SP', 'LR', 'PC');
const ArmRegistersNoName : array [0..15] of string=('R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','R11','R12','R13','R14','R15');
//const Arm64Registers : array [0..15] of string=('X0','X1','X2','X3','X4','X5','X6','X7','X8','X9','X10','X11','X12','X13','X14','X15','X16');
function SignExtend(value: int32; mostSignificantBit: integer): int32;
type
TArmDisassembler=object
private
opcode: uint32;
function Condition: string;
procedure Branch;
procedure BX;
procedure DataProcessing;
procedure MRS;
procedure MSR;
procedure MSR_flg;
procedure Mul;
procedure SingleDataTransfer;
procedure LDM_STM;
procedure SWP;
procedure SWI;
procedure CDP;
public
LastDisassembleData: TLastDisassembleData;
function disassemble(var address: ptrUint): string;
end;
implementation
{$ifndef ARMDEV}
uses processhandlerunit, disassemblerarm32, disassemblerarm64;
{$endif}
function SignExtend(value: int32; mostSignificantBit: integer): int32;
{
Signextends a given offset. mostSignificant bit defines what bit determines if it should be sign extended or not
}
begin
if (value shr mostSignificantBit)=1 then //needs to be sign extended
begin
//set bits 31 to mostSignificantBit to 1
result:=value or ($fffffff shl mostSignificantBit);
end
else
result:=value;
end;
function TArmDisassembler.Condition: string;
begin
result:=ArmConditions[opcode shr 28];
end;
procedure TArmDisassembler.Branch;
var offset: int32;
_condition: string;
begin
_condition:=condition;
if (opcode shr 24) and 1=1 then //Link bit set
begin
LastDisassembleData.opcode:='BL'+Condition;
LastDisassembleData.iscall:=true;
end
else
begin
LastDisassembleData.opcode:='B'+Condition;
LastDisassembleData.isjump:=true;
LastDisassembleData.isconditionaljump:=_condition<>'';
end;
offset:=signextend(opcode and $FFFFFF, 23) shl 2;
LastDisassembleData.parameters:=inttohex(dword(LastDisassembleData.address+8+offset),8);
end;
procedure TArmDisassembler.BX;
var
Rn: integer;
_Rn: string;
_condition: string;
begin
_condition:=condition;
LastDisassembleData.opcode:='BX'+Condition;
LastDisassembleData.isjump:=true;
LastDisassembleData.isconditionaljump:=_condition<>'';
Rn:=opcode and $F;
_Rn:=ArmRegisters[Rn];
LastDisassembleData.parameters:=_Rn;
end;
procedure TArmDisassembler.DataProcessing;
var
ImmediateOperand: integer;
OpcodeIndex: integer;
SetCondition: integer;
Operand1: integer;
Destination: integer;
Operand2: integer;
shift: integer;
rm: integer;
Rotate: integer;
Imm: integer;
shiftformat: integer;
shiftType: integer;
shiftammount: integer;
shiftRegister: integer;
shiftname: string='';
_shift: string;
_opcode: string;
_cond: string;
_S: string;
_Rd: string;
_Rn: string;
_rm: string;
_rs: string;
_op2: string;
begin
_opcode:='';
_cond:='';
_S:='';
_Rd:='';
_Rn:='';
_op2:='';
ImmediateOperand:=(opcode shr 25) and 1;
OpcodeIndex:=(opcode shr 21) and $f;
SetCondition:=(opcode shr 20) and 1;
Operand1:=(opcode shr 16) and $f;
Destination:=(opcode shr 12) and $f;
Operand2:=opcode and $fff;
_opcode:=DataProcessingOpcodes[OpcodeIndex];
_cond:=Condition;
if SetCondition=1 then
_s:='S';
_Rn:=ArmRegisters[Operand1];
_Rd:=ArmRegisters[Destination];
//build _op2
if ImmediateOperand=0 then //operand2 is a register
begin
shift:=Operand2 shr 4;
rm:=operand2 and $f;
_rm:=ArmRegisters[rm];
shiftformat:=shift and 1;
shiftType:=(shift shr 1) and 3;
case shifttype of
0: shiftname:='LSL';
1: shiftname:='LSR';
2: shiftname:='ASR';
3: shiftname:='ROR';
end;
_shift:=shiftname;
if shiftformat=0 then
begin
shiftAmmount:=(shift shr (7-4)) and $1f; //7-4 because the doc describes the shift field starting from bit 4
if shiftAmmount>0 then
_shift:=_shift+' '+inttohex(shiftammount,1)
else
_shift:='';
end
else
begin
shiftregister:=(shift shr (8-4)) and $f;
_rs:=ArmRegisters[shiftregister];
_shift:=_shift+' '+_rs;
end;
if _shift<>'' then
_op2:=_rm+','+_shift
else
_op2:=_rm;
end
else
begin
//operand2 is an immediate value
rotate:=Operand2 shr 8;
imm:=Operand2 and $ff;
_op2:=inttohex(RorDWord(imm, rotate*2),1);
end;
if _op2<>'' then
_op2:=','+_op2;
case OpcodeIndex of
13,15:
begin
LastDisassembleData.opcode:=_opcode+_cond+_S;
LastDisassembleData.parameters:=_Rd+_op2;
end;
8,9,10,11:
begin
LastDisassembleData.opcode:=_opcode+_cond;
LastDisassembleData.parameters:=_Rn+_op2;
end
else
begin
LastDisassembleData.opcode:=_opcode+_cond+_S;
LastDisassembleData.parameters:=_Rd+','+_Rn+_op2;
end;
end;
end;
procedure TArmDisassembler.MRS;
var
_cond: string;
_rd: string;
_psr: string;
Ps: integer;
Rd: integer;
begin
_cond:=Condition;
Ps:=(opcode shr 22) and 1;
if (Ps=0) then
_psr:='CPSR'
else
_psr:='SPSR';
Rd:=(opcode shr 12) and $F;
_rd:=ArmRegisters[rd];
LastDisassembleData.opcode:='MRS'+_cond;
LastDisassembleData.parameters:=_Rd+','+_psr;
end;
procedure TArmDisassembler.MSR;
var
_cond: string;
_psr: string;
_Rm: string;
Pd: integer;
Rm: integer;
I: integer;
imm, rotate: integer;
begin
_cond:=Condition;
Pd:=(opcode shr 22) and 1;
if (Pd=0) then
_psr:='CPSR'
else
_psr:='SPSR';
Rm:=opcode and $F;
_rm:=ArmRegisters[rm];
LastDisassembleData.opcode:='MSR'+_cond;
LastDisassembleData.parameters:=_psr+'_all,'+_Rm;
end;
procedure TArmDisassembler.MSR_flg;
var
_cond: string;
_psr: string;
_Rm: string;
Pd: integer;
Rm: integer;
I: integer;
imm, rotate: integer;
begin
_cond:=Condition;
Pd:=(opcode shr 22) and 1;
if (Pd=0) then
_psr:='CPSR'
else
_psr:='SPSR';
i:=(opcode shr 25) and 1;
if i=0 then
begin
Rm:=opcode and $F;
_rm:=ArmRegisters[rm];
LastDisassembleData.opcode:='MSR'+_cond;
LastDisassembleData.parameters:=_psr+'_flg,'+_Rm;
end
else
begin
rotate:=(opcode and $fff) shr 8;
imm:=(opcode and $fff) and $ff;
LastDisassembleData.opcode:='MSR'+_cond;
LastDisassembleData.parameters:=_psr+'_flg,'+inttohex(RorDWord(imm, rotate*2),1);
end;
end;
procedure TArmDisassembler.Mul;
var
_cond: string;
_S: string;
_rd: string;
_rm: string;
_rs: string;
_rn: string;
begin
if (opcode shl 20) and 1=1 then
_S:='S'
else
_S:='';
_cond:=Condition;
_rd:=ArmRegisters[opcode shl 16 and $f];
_rn:=ArmRegisters[opcode shl 12 and $f];
_rs:=ArmRegisters[opcode shl 8 and $f];
_rm:=ArmRegisters[opcode and $f];
if (opcode shl 21) and 1=1 then
begin
LastDisassembleData.opcode:='MLA'+_cond+_S;
LastDisassembleData.parameters:=_Rd+','+_Rm+','+_Rs+','+_Rn
end
else
begin
LastDisassembleData.opcode:='MUL'+_cond+_S;
LastDisassembleData.parameters:=_Rd+','+_Rm+','+_Rs;
end;
end;
procedure TArmDisassembler.SingleDataTransfer;
var
_cond: string;
_opcode: string;
_B: string;
_T: string;
_Rd: string;
_Rn: string;
_Rm: string;
_shift: string;
_U: string;
I: integer;
P: integer;
U: integer;
B: integer;
W: integer;
L: integer;
Rn: integer;
Rd: integer;
Rm: integer;
Offset: integer;
shift: integer;
shifttype: integer;
_shiftname: string='';
_shiftAmount: string;
shiftamount: integer;
_address: string;
begin
I:=(opcode shr 25) and 1;
P:=(opcode shr 24) and 1;
U:=(opcode shr 23) and 1;
B:=(opcode shr 22) and 1;
W:=(opcode shr 21) and 1;
L:=(opcode shr 20) and 1;
Rn:=(opcode shr 16) and $f;
Rd:=(opcode shr 12) and $f;
offset:=opcode and $fff;
if L=1 then
_opcode:='LDR'
else
_opcode:='STR';
if u=0 then
_U:='-'
else
_U:='';
_cond:=Condition;
if b=1 then
_B:='B'
else
_B:='';
if (W=1) and (p=0) then //w is set and p=0 (post indexed)
_T:='T'
else
_T:='';
_Rd:=ArmRegisters[Rd];
_Rn:=ArmRegisters[Rn];
if i=0 then
begin
//offset is an immediate value
if Rn=15 then //pc
begin
if u=0 then //decrease
_address:='['+inttohex(dword(LastDisassembleData.address-offset+8),8)+']'
else
_address:='['+inttohex(dword(LastDisassembleData.address+offset+8),8)+']'
end
else
begin
if offset=0 then
_address:='['+_Rn+']'
else
_address:='['+_Rn+','+_U+inttohex(dword(offset),8)+']';
end;
end
else
begin
//offset is a register
Rm:=offset and $f;
Shift:=offset shr 4;
_Rm:=ArmRegisters[Rm];
shiftType:=(shift shr 1) and 3;
case shifttype of
0: _shiftname:='LSL';
1: _shiftname:='LSR';
2: _shiftname:='ASR';
3: _shiftname:='ROR';
end;
shiftAmount:=(shift shr (7-4)) and $1f;
if shiftAmount>0 then
begin
_shiftAmount:=inttohex(shiftamount,1);
_shift:=', '+_U+_Rm+' '+_shiftname+' '+_shiftamount;
end
else
begin
_shiftAmount:='';
_shift:=', '+_Rm;
end;
if p=0 then //post index
_address:='['+_Rn+']'+_shift
else //preindexed
_address:='['+_Rn+_shift+']';
end;
if (w=1) and (p=1) then
_address:=_address+'!';
LastDisassembleData.opcode:=_opcode+_cond+_B+_T;
LastDisassembleData.parameters:=_Rd+','+_Address;
end;
procedure TArmDisassembler.LDM_STM;
var
P: integer;
U: integer;
S: integer;
W: integer;
L: integer;
Rn: integer;
RegisterList: integer;
_opcode: string;
_cond: string;
_addressingmode: string;
_rn: string;
_ex: string;
_exp: string;
_rlist: string;
i: integer;
rcount: integer;
begin
_cond:=Condition;
p:=(opcode shr 24) and 1;
u:=(opcode shr 23) and 1;
s:=(opcode shr 22) and 1;
w:=(opcode shr 21) and 1;
l:=(opcode shr 20) and 1;
Rn:=(opcode shr 16) and $f;
RegisterList:=opcode and $ffff;
_rlist:='{';
rcount:=0;
for i:=0 to 15 do
begin
if (RegisterList shr i) and 1=1 then
begin
if rcount=0 then
_rlist:=_rlist+ArmRegisters[i]
else
_rlist:=_rlist+', '+ArmRegisters[i];
inc(rcount);
end;
end;
_rlist:=_rlist+'}';
IF (rn=%1101) and (rcount>=2) then
begin
_opcode:='PUSH';
LastDisassembleData.opcode:=_opcode+_cond;
LastDisassembleData.parameters:=_rlist;
exit;
end
else
begin
if L=0 then
_opcode:='STM'
else
_opcode:='LDM';
end;
_rn:=ArmRegisters[Rn];
if w=1 then
_ex:='!'
else
_ex:='';
if s=1 then
_exp:='^'
else
_exp:='';
_addressingmode:='';
if (L=1) and (P=1) and (U=1) then
begin
if rn=13 then
_addressingmode:='ED'
else
_addressingmode:='IB';
end;
if (L=1) and (P=0) and (U=1) then
begin
if rn=13 then
_addressingmode:='FD'
else
_addressingmode:='IA';
end;
if (L=1) and (P=1) and (U=0) then
begin
if rn=13 then
_addressingmode:='EA'
else
_addressingmode:='DB';
end;
if (L=1) and (P=0) and (U=0) then
begin
if rn=13 then
_addressingmode:='FA'
else
_addressingmode:='DA';
end;
if (L=0) and (P=1) and (U=1) then
begin
if rn=13 then
_addressingmode:='FA'
else
_addressingmode:='IB';
end;
if (L=0) and (P=0) and (U=1) then
begin
if rn=13 then
_addressingmode:='EA'
else
_addressingmode:='IA';
end;
if (L=0) and (P=1) and (U=0) then
begin
if rn=13 then
_addressingmode:='FD'
else
_addressingmode:='DB';
end;
if (L=0) and (P=0) and (U=0) then
begin
if rn=13 then
_addressingmode:='ED'
else
_addressingmode:='DA';
end;
LastDisassembleData.opcode:=_opcode+_cond+_addressingmode;
LastDisassembleData.parameters:=_rn+_ex+','+_rlist+_exp;
end;
procedure TArmDisassembler.SWP;
var
_cond: string;
_B: string;
_rd: string;
_rm: string;
_rn: string;
begin
_cond:=Condition;
if (opcode shr 22) and 1=1 then
_B:='1'
else
_B:='';
_rd:=ArmRegisters[(opcode shr 12) and $f];
_rm:=ArmRegisters[opcode and $f];
_rn:=ArmRegisters[(opcode shr 16) and $f];
LastDisassembleData.opcode:='SWP'+_cond+_B;
LastDisassembleData.parameters:=_rd+','+_rm+',['+_rn+']';
end;
procedure TArmDisassembler.SWI;
begin
LastDisassembleData.opcode:='SWI'+Condition;
LastDisassembleData.parameters:=inttohex(opcode and $FFFFFF,1);
end;
procedure FloatingPointDataInstruction(var LastDisassembleData: TLastDisassembleData);
var
opcode: dword;
cond: byte;
t: byte;
opc1, opc2, opc3, opc4: byte;
condition: string;
D, Vn, Vd, sz, N, M, Vm: byte;
cc: byte;
begin
opcode:=pdword(LastDisassembleData.Bytes)^;
if lastdisassembledata.Disassembler=dcArm then
begin
cond:=(opcode shr 28) and $f;
if (cond=$f) then
t:=1
else
t:=0;
condition:=ArmConditions[cond];
end
else
begin
opcode:=(opcode shr 16) or (opcode shl 16);
t:=(opcode shr 28) and 1;
pdword(@lastdisassembledata.Bytes[0])^:=opcode;
condition:='';
end;
opc1:=(opcode shr 20) and $f;
opc2:=(opcode shr 16) and $f;
opc3:=(opcode shr 6) and 3;
opc4:=opcode and $f;
sz:=(opcode shr 8) and 1;
D:=(opcode shr 22) and 1;
Vn:=(opcode shr 16) and $f;
Vd:=(opcode shr 12) and $f;
N:=(opcode shr 7) and 1;
M:=(opcode shr 5) and 1;
Vm:=opcode and $f;
if sz=0 then
begin
Vn:=(Vn shl 1) or N;
Vm:=(Vm shl 1) or M;
Vd:=(Vd shl 1) or D;
LastDisassembleData.parameters:='S'+inttostr(vd)+', S'+inttostr(vn)+', S'+inttostr(Vm);
end
else
begin
Vn:=(N shl 4) or Vn;
Vm:=(M shl 4) or Vm;
Vd:=(D shl 4) or Vd;
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
end;
case (t shl 4) or opc1 of
0,4: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VMLS' else LastDisassembleData.opcode:='VMLA';
1,5: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VNMLA' else LastDisassembleData.opcode:='VNMLS';
2,6: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VNMUL' else LastDisassembleData.opcode:='VMUL';
3,7: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VADD' else LastDisassembleData.opcode:='VSUB';
8,12: if (opc3 and 1)=0 then LastDisassembleData.opcode:='VDIV';
9,13: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VFNMA' else LastDisassembleData.opcode:='VFNMS';
10,14: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VFMS' else LastDisassembleData.opcode:='VFMA';
16..23:
begin
case (opcode shr 20) and 3 of
0: LastDisassembleData.opcode:='VSELEQ';
1: LastDisassembleData.opcode:='VSELVS';
2: LastDisassembleData.opcode:='VSELGE';
3: LastDisassembleData.opcode:='VSELGT';
end;
end;
24,28: if (opc3 and 1)=1 then LastDisassembleData.opcode:='VMINNM' else LastDisassembleData.opcode:='VMAXNM';
11,15, 27, 31:
begin
//other:
exit;
end;
end;
if sz=0 then
LastDisassembleData.opcode:=LastDisassembleData.opcode+condition+'.F32'
else
LastDisassembleData.opcode:=LastDisassembleData.opcode+condition+'.F64';
if lastdisassembledata.Disassembler=dcThumb then //undo the wordswap
begin
opcode:=(opcode shr 16) or (opcode shl 16);
pdword(@lastdisassembledata.Bytes[0])^:=opcode;
end;
end;
procedure TArmDisassembler.CDP;
var
CP_Opc: integer;
CRn: integer;
CRd: integer;
CPn: integer;
CP: integer;
CRm: integer;
_pn: string;
_cd,_cn,_cm: string;
_expression1,_expression2: string;
begin
CP_Opc:=(opcode shr 20) and $f; //
CRd:=(opcode shr 12) and $f; //
CRn:=(opcode shr 16) and $f; //
CRm:=opcode and $f; //
CPn:=(opcode shr 8) and $f;
CP:=(opcode shr 5) and $7; //
if (CPn in [10,11]) and ((opcode and $10)=$10) then
begin
FloatingPointDataInstruction(LastDisassembleData);
exit;
end;
_expression1:=inttohex(CP_OPC,1);
if cp<>0 then
_expression2:=inttohex(CP,1)
else
_expression2:='';
_pn:=inttohex(cp,1);
_cd:='c'+inttostr(CRd);
_cn:='c'+inttostr(CRn);
_cm:='c'+inttostr(CRm);
//CDP{cond} p#,<expression1>,cd,cn,cm{,<expression2>}
LastDisassembleData.opcode:='CDP'+Condition;
LastDisassembleData.parameters:=_pn+','+_expression1+','+_cd+','+_cn+','+_cm+_expression2;
end;
procedure ASIMD_3RegSL(var LastDisassembleData: TLastDisassembleData);
var
opcode: dword;
u,c,a,b: byte;
d: byte;
size: byte;
Vn, Vd, op, N, Q, M, Vm: byte;
_datatype: string;
begin
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
if LastDisassembleData.Disassembler=dcThumb then
u:=(opcode shr 28) and 1
else
u:=(opcode shr 24) and 1;
a:=(opcode shr 8) and $f;
b:=(opcode shr 4) and 1;
c:=(opcode shr 20) and 3;
D:=(opcode shr 22) and 1;
size:=(opcode shr 20) and 3;
Vn:=(opcode shr 16) and $f;
Vd:=(opcode shr 12) and $f;
op:=(opcode shr 9) and 1;
N:=(opcode shr 7) and 1;
Q:=(opcode shr 6) and 1;
M:=(opcode shr 5) and 1;
Vm:=opcode and $f;
Vn:=(N shl 4) or Vn;
Vm:=(M shl 4) or Vm;
Vd:=(D shl 4) or Vd;
if u=0 then
_datatype:='S'
else
_datatype:='U';
case size of
0: _datatype:=_datatype+'8';
1: _datatype:=_datatype+'16';
2: _datatype:=_datatype+'32';
3: _datatype:=_datatype+'64'; //?
end;
if q=1 then
LastDisassembleData.parameters:='.'+_datatype+' '+'D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm)
else
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', Q'+inttostr(Vm);
case a of
0: if b=0 then LastDisassembleData.opcode:='VHADD' else LastDisassembleData.opcode:='VQADD';
1:
begin
if b=0 then LastDisassembleData.opcode:='VRHADD' else
begin
case (u shl 2) or c of
0: LastDisassembleData.opcode:='VAND';
1: LastDisassembleData.opcode:='VBIC';
2: LastDisassembleData.opcode:='VORR';
3: LastDisassembleData.opcode:='VORN';
4: LastDisassembleData.opcode:='VEOR';
5: LastDisassembleData.opcode:='VBSL';
6: LastDisassembleData.opcode:='VBIT';
7: LastDisassembleData.opcode:='VBIF';
end;
end;
end;
2: if b=0 then LastDisassembleData.opcode:='VHSUB' else LastDisassembleData.opcode:='VQSUB';
3: if b=0 then LastDisassembleData.opcode:='VCGT' else LastDisassembleData.opcode:='VCGE';
4: if b=0 then LastDisassembleData.opcode:='VSHL' else LastDisassembleData.opcode:='VQSHL';
5: if b=0 then LastDisassembleData.opcode:='VRSHL' else LastDisassembleData.opcode:='VQRSHL';
6: if b=0 then LastDisassembleData.opcode:='VMAX' else LastDisassembleData.opcode:='VMIN';
7: if b=0 then LastDisassembleData.opcode:='VABD' else LastDisassembleData.opcode:='VABA';
8: if b=0 then
begin
if u=0 then LastDisassembleData.opcode:='VADD' else LastDisassembleData.opcode:='VSUB';
end
else
begin
if u=0 then LastDisassembleData.opcode:='VTST' else LastDisassembleData.opcode:='VCEQ';
end;
9: if b=0 then
begin
if u=0 then LastDisassembleData.opcode:='VMLA' else LastDisassembleData.opcode:='VMLS';
end
else LastDisassembleData.opcode:='VMUL';
10: if b=0 then LastDisassembleData.opcode:='VPMAX' else LastDisassembleData.opcode:='VPMIN';
11: if b=0 then
begin
if u=0 then LastDisassembleData.opcode:='VQDMULH' else LastDisassembleData.opcode:='VQRDMULH';
end
else LastDisassembleData.opcode:='VPADD';
12: case (b shl 3) or (u shl 2) or c of
0: LastDisassembleData.opcode:='SHA1C';
1: LastDisassembleData.opcode:='SHA1P';
2: LastDisassembleData.opcode:='SHA1M';
3: LastDisassembleData.opcode:='SHA1SU0';
4: LastDisassembleData.opcode:='SHA256H';
5: LastDisassembleData.opcode:='SHA256H2';
6: LastDisassembleData.opcode:='SHA256SU1';
8: LastDisassembleData.opcode:='VFMA';
10:LastDisassembleData.opcode:='VFMS';
end;
13: case (b shl 3) or (u shl 2) or c of
0,1: LastDisassembleData.opcode:='VADD';
2,3: LastDisassembleData.opcode:='VSUB';
4,5: LastDisassembleData.opcode:='VPADD';
6,7: LastDisassembleData.opcode:='VABD';
8: LastDisassembleData.opcode:='VMLA';
10: LastDisassembleData.opcode:='VMLS';
12,13: LastDisassembleData.opcode:='VMUL';
end;
14: case (b shl 3) or (u shl 2) or c of
0,1: LastDisassembleData.opcode:='VCEQ';
4,5: LastDisassembleData.opcode:='VCGE';
6,7: LastDisassembleData.opcode:='VCGT';
12: LastDisassembleData.opcode:='VACGE';
14: LastDisassembleData.opcode:='VACGT';
end;
15: case (b shl 3) or (u shl 2) or c of
0: LastDisassembleData.opcode:='VMAX';
2: LastDisassembleData.opcode:='VMIN';
4: LastDisassembleData.opcode:='VPMAX';
6: LastDisassembleData.opcode:='VPMIN';
8,9: LastDisassembleData.opcode:='VRECPS';
10,11: LastDisassembleData.opcode:='VRSQRTS';
12: LastDisassembleData.opcode:='VMAXNM';
14: LastDisassembleData.opcode:='VMINNM';
end;
end;
end;
procedure ASIMD_1Reg_ModImm(var LastDisassembleData: TLastDisassembleData);
var opcode: dword;
a,b,c,d,cmode,op,e,f,g,h: byte;
b2: byte;
q: byte;
Vd: byte;
abcdefgh: byte;
constant: qword;
_dt: string='';
a32: dword;
begin
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
if LastDisassembleData.Disassembler=dcThumb then
a:=(opcode shr 28) and 1
else
a:=(opcode shr 24) and 1;
b:=(opcode shr 18) and 1;
c:=(opcode shr 17) and 1;
d:=(opcode shr 16) and 1;
cmode:=(opcode shr 8) and $f;
Q:=(opcode shr 6) and 1;
op:=(opcode shr 5) and 1;
e:=(opcode shr 3) and 1;
f:=(opcode shr 2) and 1;
g:=(opcode shr 1) and 1;
h:=opcode and 1;
Vd:=((opcode shr (22-4)) and $1) or (opcode shr 12) and $f;
abcdefgh:=(a shl 7) or (b shl 6) or (c shl 5) or (d shl 4) or (e shl 3) or (f shl 2) or (g shl 1) or h;
constant:=0;
case cmode of
0:
begin
constant:=(qword(abcdefgh) shl 32) or abcdefgh;
_dt:='I32';
end;
2:
begin
constant:=(qword(abcdefgh) shl 40) or (qword(abcdefgh) shl 8);
_dt:='I32';
end;
4:
begin
constant:=(qword(abcdefgh) shl 48) or (qword(abcdefgh) shl 16);
_dt:='I32';
end;
6:
begin
constant:=(qword(abcdefgh) shl 56) or (qword(abcdefgh) shl 24);
_dt:='I32';
end;
8:
begin
constant:=(qword(abcdefgh) shl 48) or (qword(abcdefgh) shl 32) or (qword(abcdefgh) shl 16) or abcdefgh;
_dt:='I16';
end;
10:
begin
constant:=(qword(abcdefgh) shl 56) or (qword(abcdefgh) shl 40) or (qword(abcdefgh) shl 24) or (abcdefgh shl 8);
_dt:='I16';
end;
12:
begin
constant:=(qword(abcdefgh) shl 40) or (qword($ff) shl 32) or (qword(abcdefgh) shl 8) or ($ff);
_dt:='I32';
end;
13:
begin
constant:=(qword(abcdefgh) shl 48) or (qword($ff) shl 40) or (qword($ff) shl 32) or (qword(abcdefgh) shl 16) or (qword($ff) shl 8) or ($ff);
_dt:='I32';
end;
14:
begin
if op=0 then
begin
constant:=(qword(abcdefgh) shl 56) or (qword(abcdefgh) shl 48) or (qword(abcdefgh) shl 40) or (qword(abcdefgh) shl 32) or (qword(abcdefgh) shl 24) or (abcdefgh shl 16) or (abcdefgh shl 8);
_dt:='I8';
end
else
begin
a:=(a shl 7) or (a shl 6) or (a shl 5) or (a shl 4) or (a shl 3) or (a shl 2) or (a shl 1) or a;
b:=(b shl 7) or (b shl 6) or (b shl 5) or (b shl 4) or (b shl 3) or (b shl 2) or (b shl 1) or b;
c:=(c shl 7) or (c shl 6) or (c shl 5) or (c shl 4) or (c shl 3) or (c shl 2) or (c shl 1) or c;
d:=(d shl 7) or (d shl 6) or (d shl 5) or (d shl 4) or (d shl 3) or (d shl 2) or (d shl 1) or d;
e:=(e shl 7) or (e shl 6) or (e shl 5) or (e shl 4) or (e shl 3) or (e shl 2) or (e shl 1) or e;
f:=(f shl 7) or (f shl 6) or (f shl 5) or (f shl 4) or (f shl 3) or (f shl 2) or (f shl 1) or f;
g:=(g shl 7) or (g shl 6) or (g shl 5) or (g shl 4) or (g shl 3) or (g shl 2) or (g shl 1) or g;
h:=(h shl 7) or (h shl 6) or (h shl 5) or (h shl 4) or (h shl 3) or (h shl 2) or (h shl 1) or h;
constant:=(qword(a) shl 56) or (qword(b) shl 48) or (qword(c) shl 40) or (qword(d) shl 32) or (qword(e) shl 24) or (qword(f) shl 16) or (qword(g) shl 16) or qword(h);
_dt:='I64';
end;
end;
15:
begin
if op=0 then
begin
b2:=(not b) and 1;
a32:=0;
a32:=(a shl 31) or (b2 shl 30) or (b shl 29) or (b shl 28) or (b shl 27) or (b shl 26) or (b shl 25) or (c shl 24) or (d shl 23) or (e shl 22) or (e shl 21) or (f shl 20) or (g shl 19) or (h shl 18);
constant:=(qword(a32) shl 32) or a32;
end
else
begin
constant:=qword($BADBADBADBADBAD)
end;
end;
end;
case (op shl 4) or cmode of
0,2,4,6: LastDisassembleData.opcode:='VMOV.'+_dt;
1,3,5,7: LastDisassembleData.opcode:='VORR.'+_dt;
8,10: LastDisassembleData.opcode:='VMOV.'+_dt;
9,11: LastDisassembleData.opcode:='VORR.'+_dt;
12,13,14,15: LastDisassembleData.opcode:='VMOV.'+_dt;
16,18,20,22: LastDisassembleData.opcode:='VMVN.'+_dt;
17,19,21,23: LastDisassembleData.opcode:='VBIC.'+_dt;
24,26: LastDisassembleData.opcode:='VMVN.'+_dt;
25,27: LastDisassembleData.opcode:='VBIC.'+_dt;
28,29: LastDisassembleData.opcode:='VMVN.'+_dt;
30: LastDisassembleData.opcode:='VMOV.'+_dt;
end;
if Q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', '+inttohex(constant,1)
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', '+inttohex(constant,1);
end;
procedure ASIMD_2Reg_Shift(var LastDisassembleData: TLastDisassembleData);
var opcode: dword;
u: byte;
imm3, imm6: byte;
M, D,A,L,B,Q: byte;
Vd, Vm: byte;
size: integer;
_type, _size: string;
limm3: byte;
imm: byte;
esize: byte;
elements: byte;
op: byte;
_dt1: string='';
_dt2: string='';
begin
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
imm:=0;
if LastDisassembleData.Disassembler=dcThumb then
u:=(opcode shr 28) and 1
else
u:=(opcode shr 24) and 1;
d:=(opcode shr 22) and 1;
imm3:=(opcode shr 19) and $7;
imm6:=(opcode shr 16) and $3f;
Vd:=(opcode shr 12) and $f;
a:=(opcode shr 8) and $f;
op:=(opcode shr 8) and 1;
l:=(opcode shr 7) and 1;
b:=(opcode shr 6) and 1;
q:=b;
m:=(opcode shr 5) and 1;
Vm:=opcode and $f;
Vm:=(m shl 4) or vm;
Vd:=(d shl 4) or vd;
limm3:=(l shl 3) or imm3;
if (limm3=0) then ASIMD_1Reg_ModImm(LastDisassembleData);
_type:='';
//size:
size:=8;
if (limm3 and 1)=1 then size:=8 else
if (limm3 and 2)=2 then size:=16 else
if (limm3 and 4)=4 then size:=32 else
if (limm3 and 8)=8 then size:=64;
esize:=size;
_size:=inttostr(size);
//imm:
if a in [0,1,2,3,4] then
begin
if size=32 then size:=64;
imm:=size-imm6;
end;
if a in [5,6,7] then
begin
case size of
8: imm:=imm6-8;
16: imm:=imm6-16;
32: imm:=imm6-32;
64: imm:=imm6;
end;
end;
//_type:
if u=0 then _type:='S' else _type:='U';
if Q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(vm)+', '+inttohex(imm,1)
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(imm,1);
//instruction:
case A of
0: LastDisassembleData.opcode:='VSHR'+_type+_size;
1: LastDisassembleData.opcode:='VSRA'+_type+_size;
2: LastDisassembleData.opcode:='VRSHR'+_type+_size;
3: LastDisassembleData.opcode:='VRSRA'+_type+_size;
4: if u=1 then LastDisassembleData.opcode:='VSRI'+_size;
5: if u=0 then LastDisassembleData.opcode:='VSHL.I'+_size else LastDisassembleData.opcode:='VSLI'+_type+_size;
6: LastDisassembleData.opcode:='VQSHLU'+_type+_size;
7: LastDisassembleData.opcode:='VQSHL'+_type+_size;
8:
begin
size:=size*2;
_size:=inttostr(size);
imm:=size-imm6;
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(imm,1);
case (u shl 3) or (b shl 2) or l of
0: LastDisassembleData.opcode:='VSHRN.I'+_size;
2: LastDisassembleData.opcode:='VRSHRN.I'+_size;
4: LastDisassembleData.opcode:='VQSHRUN.I'+_type+_size;
6: LastDisassembleData.opcode:='VQRSHRUN.I'+_type+_size;
end;
end;
9:
begin
size:=size*2;
_size:=inttostr(size);
imm:=size-imm6;
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(imm,1);
case (b shl 2) or l of
0: LastDisassembleData.opcode:='VSHRN.I'+_size;
2: LastDisassembleData.opcode:='VRSHRN.I'+_size;
end;
end;
10:
begin
if (b=0) and (l=0) then
begin
imm:=imm6-esize;
if imm=0 then
begin
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(vm);
LastDisassembleData.opcode:='VMOVL';
end
else
begin
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(imm,1);
LastDisassembleData.opcode:='VSHLL'+_type+_size;
end;
end;
end;
14,15:
begin
case (op shl 1) or U of
0:
begin
_dt1:='F32';
_dt2:='S32';
end;
1:
begin
_dt1:='F32';
_dt2:='U32';
end;
2:
begin
_dt1:='S32';
_dt2:='F32';
end;
3:
begin
_dt1:='U32';
_dt2:='F32';
end;
end;
LastDisassembleData.opcode:='VCVT.'+_dt1+'.'+_dt2;
if Q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(vm)+', '+inttohex(64-imm6,1)
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(vm)+', '+inttohex(64-imm6,1)
end;
end;
end;
procedure ASIMD_3Reg_DL(var LastDisassembleData: TLastDisassembleData);
var opcode: dword;
u,b,a: byte;
d, size, Vn, Vd, op, N,M, Vm: byte;
_datatype: string;
begin
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
if LastDisassembleData.Disassembler=dcThumb then
u:=(opcode shr 28) and 1
else
u:=(opcode shr 24) and 1;
b:=(opcode shr 20) and 3;
a:=(opcode shr 8) and $f;
D:=(opcode shr 22) and 1;
size:=(opcode shr 20) and 3;
Vn:=(opcode shr 16) and $f;
Vd:=(opcode shr 12) and $f;
op:=(opcode shr 9) and 1;
N:=(opcode shr 7) and 1;
M:=(opcode shr 5) and 1;
Vm:=opcode and $f;
Vn:=(N shl 4) or Vn;
Vm:=(M shl 4) or Vm;
Vd:=(D shl 4) or Vd;
if u=0 then
_datatype:='S'
else
_datatype:='U';
case size of
0: _datatype:=_datatype+'8';
1: _datatype:=_datatype+'16';
2: _datatype:=_datatype+'32';
3: _datatype:=_datatype+'64'; //?
end;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
case a of
0: LastDisassembleData.opcode:='VADDL';
1:
begin
LastDisassembleData.opcode:='VADDW';
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm);
end;
2: LastDisassembleData.opcode:='VSUBL';
3:
begin
LastDisassembleData.opcode:='VSUBL';
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm);
end;
4: if u=0 then LastDisassembleData.opcode:='VADDHN' else LastDisassembleData.opcode:='VRADDHN';
5: LastDisassembleData.opcode:='VABAL';
6: if u=0 then LastDisassembleData.opcode:='VSUBHN' else LastDisassembleData.opcode:='VRSUBHN';
7: LastDisassembleData.opcode:='VABDL';
8: LastDisassembleData.opcode:='VMLAL';
9: if u=0 then LastDisassembleData.opcode:='VQDMLAL';
10: LastDisassembleData.opcode:='VMLSL';
11: LastDisassembleData.opcode:='VQDMLSL';
12,14: LastDisassembleData.opcode:='VMULL';
13: LastDisassembleData.opcode:='VQDMULL';
end;
end;
procedure ASIMD_2Reg_Scalar(var LastDisassembleData: TLastDisassembleData);
var opcode: dword;
q,u,b,a: byte;
d, size, Vn, Vd, op, F,N,M, Vm: byte;
_datatype: string='';
begin
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
if LastDisassembleData.Disassembler=dcThumb then
u:=(opcode shr 28) and 1
else
u:=(opcode shr 24) and 1;
q:=u;
b:=(opcode shr 20) and 3;
a:=(opcode shr 8) and $f;
D:=(opcode shr 22) and 1;
size:=(opcode shr 20) and 3;
Vn:=(opcode shr 16) and $f;
Vd:=(opcode shr 12) and $f;
op:=(opcode shr 9) and 1;
F:=(opcode shr 8) and 1;
N:=(opcode shr 7) and 1;
M:=(opcode shr 5) and 1;
Vm:=opcode and $f;
Vn:=(N shl 4) or Vn;
Vm:=(M shl 4) or Vm;
Vd:=(D shl 4) or Vd;
case size of
0: _datatype:='8';
1: _datatype:='16';
2: _datatype:='32';
3: _datatype:='64'; //?
end;
case a of
0,1:
begin
if F=0 then _datatype:='I'+_datatype else _datatype:='F'+_datatype;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VMLA';
end;
2:
begin
if U=0 then _datatype:='S'+_datatype else _datatype:='U'+_datatype;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VMLAL';
end;
3:
begin
_datatype:='S'+_datatype;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VQDMLAL';
end;
4,5:
begin
if F=0 then _datatype:='I'+_datatype else _datatype:='F'+_datatype;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VMLA';
end;
6:
begin
if U=0 then _datatype:='S'+_datatype else _datatype:='U'+_datatype;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VMLSL';
end;
7:
begin
_datatype:='S'+_datatype;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VQDMLSL';
end;
8,9:
begin
if F=0 then _datatype:='I'+_datatype else _datatype:='F'+_datatype;
if q=1 then
LastDisassembleData.parameters:='.'+_datatype+' '+'D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm)
else
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VMUL';
end;
10:
begin
if U=0 then _datatype:='S'+_datatype else _datatype:='U'+_datatype;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VMULL';
end;
11:
begin
_datatype:='S'+_datatype;
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VQDMULL';
end;
12:
begin
_datatype:='S'+_datatype;
if q=1 then
LastDisassembleData.parameters:='.'+_datatype+' '+'D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm)
else
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VQDMULH';
end;
13:
begin
_datatype:='S'+_datatype;
if q=1 then
LastDisassembleData.parameters:='.'+_datatype+' '+'D'+inttostr(vd)+', D'+inttostr(vn)+', D'+inttostr(Vm)
else
LastDisassembleData.parameters:='.'+_datatype+' '+'Q'+inttostr(vd)+', Q'+inttostr(vn)+', D'+inttostr(Vm);
LastDisassembleData.opcode:='VQRDMULH';
end;
end;
end;
procedure VEXT(var LastDisassembleData: TLastDisassembleData);
var
opcode: dword;
D, Vn, Vd, imm4, N, Q, M, Vm: byte;
begin
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
D:=(opcode shr 22) and 1;
Vn:=(opcode shr 16) and $f;
Vd:=(opcode shr 12) and $f;
imm4:=(opcode shr 8) and $f;
N:=(opcode shr 7) and 1;
Q:=(opcode shr 6) and 1;
M:=(opcode shr 5) and 1;
Vm:=opcode and $f;
Vn:=(N shl 4) or Vn;
Vm:=(M shl 4) or Vm;
Vd:=(D shl 4) or Vd;
if q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vn)+', D'+inttostr(Vm)+' '+inttohex(imm4,1)
else
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vn)+', D'+inttostr(Vm)+' '+inttohex(imm4,1);
LastDisassembleData.opcode:='VEXT.8';
end;
procedure ASIMD_2Reg_Misc(var LastDisassembleData: TLastDisassembleData);
var opcode: dword;
u,b,a: byte;
q,d, size, Vn, Vd, op, F,N,M, Vm: byte;
sz: byte;
_dt: string='';
_dt2: string='';
_sU, _sf: string;
begin
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
if LastDisassembleData.Disassembler=dcThumb then
u:=(opcode shr 28) and 1
else
u:=(opcode shr 24) and 1;
b:=(opcode shr 6) and $1f;
a:=(opcode shr 16) and $3;
D:=(opcode shr 22) and 1;
size:=(opcode shr 18) and 3;
Vn:=(opcode shr 16) and $f;
Vd:=(opcode shr 12) and $f;
op:=(opcode shr 7) and 1;
F:=(opcode shr 10) and 1;
N:=(opcode shr 7) and 1;
Q:=(opcode shr 6) and 1;
M:=(opcode shr 5) and 1;
Vm:=opcode and $f;
Vn:=(N shl 4) or Vn;
Vm:=(M shl 4) or Vm;
Vd:=(D shl 4) or Vd;
case size of
0: _dt:='8';
1: _dt:='16';
2: _dt:='32';
3: _dt:='64';
end;
case size of
0: _dt2:='16';
1: _dt2:='32';
2: _dt2:='64';
end;
if op=0 then _SU:='S' else _sU:='U';
if f=0 then _sf:='S' else _sf:='F';
case a of
0:
begin
case b of
0..11,
16..31: if q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm)
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm);
12..15: LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm);
end;
case b of
0,1: LastDisassembleData.opcode:='VREV64.'+_dt;
2,3: LastDisassembleData.opcode:='VREV32.'+_dt;
4,5: LastDisassembleData.opcode:='VREV16.'+_dt;
8..11: LastDisassembleData.opcode:='VPADDL.'+_sU+_dt;
12: LastDisassembleData.opcode:='AESE.'+_dt;
13: LastDisassembleData.opcode:='AESD.'+_dt;
14: LastDisassembleData.opcode:='AESMC.'+_dt;
15: LastDisassembleData.opcode:='AESIMC.'+_dt;
16,17: LastDisassembleData.opcode:='VCLS.S'+_dt;
18,19: LastDisassembleData.opcode:='VCLZ.I'+_dt;
20,21: LastDisassembleData.opcode:='VCNT.8';
22,23: LastDisassembleData.opcode:='VMVN';
24,27: LastDisassembleData.opcode:='VPADAL.'+_sU+_dt;
28,29: LastDisassembleData.opcode:='VQABS.S'+_dt;
30,31: LastDisassembleData.opcode:='VQNEG.S'+_dt;
end;
end;
1:
begin
case (b shr 1) and 7 of
0..4: if q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm)+', 0'
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm)+', 0';
5: LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm);
6,7: if q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm)
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm);
end;
case (b shr 1) and 7 of
0: LastDisassembleData.opcode:='VCGT.'+_sf+_dt;
1: LastDisassembleData.opcode:='VCGE.'+_sf+_dt;
2: LastDisassembleData.opcode:='VCEQ.'+_sf+_dt;
3: LastDisassembleData.opcode:='VCLE.'+_sf+_dt;
4: LastDisassembleData.opcode:='VCLT.'+_sf+_dt;
5: LastDisassembleData.opcode:='SHA1H.32';
6: LastDisassembleData.opcode:='VABS'+_sf+_dt;
7: LastDisassembleData.opcode:='VNEG.'+_sf+_dt;
end;
end;
2:
begin
if q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm)
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm);
case b of
0,1: LastDisassembleData.opcode:='VSWP';
2,3: LastDisassembleData.opcode:='VTRN.'+_dt;
4,5: LastDisassembleData.opcode:='VUZP.'+_dt;
6,7: LastDisassembleData.opcode:='VZIP.'+_dt;
8:
begin
LastDisassembleData.opcode:='VMOVN.I'+_dt;
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm);
end;
9:
begin
LastDisassembleData.opcode:='VQMOVUN.S'+_dt2;
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm);
end;
10:
begin
LastDisassembleData.opcode:='VQMOVN.S'+_dt2;
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm);
end;
11:
begin
if size=0 then _dt:='8';
LastDisassembleData.opcode:='VQMOVN.U'+_dt2;
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm);
end;
12:
begin
LastDisassembleData.opcode:='VSHLL';
LastDisassembleData.parameters:='Q'+inttostr(vd)+', D'+inttostr(Vm)+', '+inttohex(size,1);
end;
14:
begin
LastDisassembleData.opcode:='SHA1SU1.32';
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm);
end;
15:
begin
LastDisassembleData.opcode:='SHA1SU0.32';
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(vn)+', Q'+inttostr(Vm);
end;
16, 17: LastDisassembleData.opcode:='VRINTN.F32.F32';
18, 19: LastDisassembleData.opcode:='VRINTX.F32.F32';
20, 21: LastDisassembleData.opcode:='VRINTA.F32.F32';
22, 23: LastDisassembleData.opcode:='VRINTZ.F32.F32';
26, 27: LastDisassembleData.opcode:='VRINTM.F32.F32';
30, 31: LastDisassembleData.opcode:='VRINTP.F32.F32';
24:
begin
LastDisassembleData.opcode:='VCVT.F16.F32';
LastDisassembleData.parameters:='D'+inttostr(vd)+', Q'+inttostr(Vm);
end;
28:
begin
LastDisassembleData.opcode:='VCVT.F32.F16';
LastDisassembleData.parameters:='Q'+inttostr(vd)+', D'+inttostr(Vm);
end;
end;
end;
3:
begin
if q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm)
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm);
case b shr 2 of
0: LastDisassembleData.opcode:='VCVTA.F32';
1: LastDisassembleData.opcode:='VCVTN.F32';
2: LastDisassembleData.opcode:='VCVTP.F32';
3: LastDisassembleData.opcode:='VCVTN.F32';
4,5:
begin
if ((b shr 1) and 1)=0 then LastDisassembleData.opcode:='VRECPE' else LastDisassembleData.opcode:='VRSQRTE';
if f=1 then
LastDisassembleData.opcode:=LastDisassembleData.opcode+'F32'
else
LastDisassembleData.opcode:=LastDisassembleData.opcode+'S32';
end;
6,7:
begin
case (opcode shr 7) and 3 of
0: LastDisassembleData.opcode:='VCVT.F32.S32';
1: LastDisassembleData.opcode:='VCVT.F32.U32';
2: LastDisassembleData.opcode:='VCVT.S32.F32';
3: LastDisassembleData.opcode:='VCVT.U32.F32';
end;
end;
end;
end;
end;
end;
procedure VTBL_VTBLX(var LastDisassembleData: TLastDisassembleData);
var
opcode: dword;
D, Vn, Vd, len, N, op, M, Vm: byte;
_list: string;
i: integer;
begin
_list:='';
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
D:=(opcode shr 22) and 1;
Vn:=(opcode shr 16) and $f;
Vd:=(opcode shr 12) and $f;
len:=(opcode shr 8) and 3;
N:=(opcode shr 7) and 1;
op:=(opcode shr 6) and 1;
M:=(opcode shr 5) and 1;
Vm:=opcode and $f;
Vn:=(N shl 4) or Vn;
Vm:=(M shl 4) or Vm;
Vd:=(D shl 4) or Vd;
for i:=0 to len-1 do
begin
_list:=_list+'D'+inttostr(Vn+i);
if i<len-1 then
_list:=_list+', ';
end;
LastDisassembleData.parameters:='D'+inttostr(vd)+', {'+_list+'} D'+inttostr(Vm);
if op=0 then
LastDisassembleData.opcode:='VTBL.8'
else
LastDisassembleData.opcode:='VTBX.8';
end;
procedure VDUP_Scalar(var LastDisassembleData: TLastDisassembleData);
var
opcode: dword;
D, imm4, Vd, Q, M, Vm: byte;
size, index: byte;
begin
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
D:=(opcode shr 22) and 1;
imm4:=(opcode shr 16) and $f;
Vd:=(opcode shr 12) and $f;
Q:=(opcode shr 6) and 1;
M:=(opcode shr 5) and 1;
Vm:=opcode and $f;
Vm:=(M shl 4) or Vm;
Vd:=(D shl 4) or Vd;
size:=0;
index:=0;
if (imm4 and 1)=1 then
begin
size:=8;
index:=imm4 shr 1;
end
else
if (imm4 and 2)=2 then
begin
size:=16;
index:=imm4 shr 2;
end
else
if (imm4 and 4)=4 then
begin
size:=32;
index:=imm4 shr 3;
end;
if q=0 then
LastDisassembleData.parameters:='D'+inttostr(vd)+', D'+inttostr(Vm)+'['+inttostr(index)+']'
else
LastDisassembleData.parameters:='Q'+inttostr(vd)+', Q'+inttostr(Vm)+'['+inttostr(index)+']';
LastDisassembleData.opcode:='VDUP.'+inttostr(size);
end;
procedure Advanced_SIMD_Data_Processing(var LastDisassembleData: TLastDisassembleData);
//called by both the arm and thumb disassembler
var opcode: dword; u,a,b,c:byte;
begin
opcode:=pdword(LastDisassembleData.Bytes)^;
if lastdisassembledata.Disassembler=dcArm then
u:=(opcode shr 24) and 1
else
begin
opcode:=(opcode shr 16) or (opcode shl 16);
u:=(opcode shr 28) and 1;
pdword(@lastdisassembledata.Bytes[0])^:=opcode;
end;
a:=(opcode shr 19) and $1f;
b:=(opcode shr 8) and $f;
c:=opcode and $f;
if (a shr 4) and 1=0 then ASIMD_3RegSL(LastDisassembleData)
else
begin
if ((c and 9)=1) then
begin
case a and $7 of
0: ASIMD_1Reg_ModImm(LastDisassembleData);
1..7: ASIMD_2Reg_Shift(LastDisassembleData);
end;
end
else
if ((c and 9)=9) then
begin
ASIMD_2Reg_Shift(LastDisassembleData);
end
else
if ((a and $7) in [0..5]) and ((c and 5)=0) then
begin
ASIMD_3Reg_DL(LastDisassembleData);
end
else
if ((a and $7) in [0..5]) and ((c and 5)=4) then
begin
ASIMD_2Reg_Scalar(LastDisassembleData);
end
else
if (u=0) and ((a and $16)=$16) and ((c and 1)=0) then
begin
VEXT(LastDisassembleData);
end
else
if (u=1) and ((a and $16)=$16) and ((c and 1)=0) then
begin
if (b and 8)=0 then
begin
ASIMD_2Reg_Misc(LastDisassembleData);
end
else
if (b and $c)=8 then
begin
VTBL_VTBLX(LastDisassembleData);
end
else
if (b=$c) then
begin
VDUP_Scalar(LastDisassembleData);
end;
end;
end;
if lastdisassembledata.Disassembler=dcThumb then //undo the wordswap
begin
opcode:=(opcode shr 16) or (opcode shl 16);
pdword(@lastdisassembledata.Bytes[0])^:=opcode;
end;
end;
function TArmDisassembler.Disassemble(var address: ptrUint): string;
var
i: integer;
x: ptruint;
thumbdisassembler: TThumbDisassembler;
arm32disassembler: TArm32Instructionset;
arm64disassembler: TArm64Instructionset;
begin
result:='';
if processhandler.is64Bit then
begin
result:=arm64disassembler.Disassemble(address);
lastdisassembledata:=arm64disassembler.LastDisassembleData;
exit;
end
else
begin
if (address and 1) = 1 then //thumb
begin
result:=thumbdisassembler.Disassemble(address);
LastDisassembleData:=thumbdisassembler.LastDisassembleData;
exit;
end;
if (address and 3) = 0 then
begin
result:=arm32disassembler.Disassemble(address);
lastdisassembledata:=arm32disassembler.LastDisassembleData;
exit;
end;
end;
//obsolete:
{$ifdef ARMDEV}
opcode:=pdword(address)^;
setlength(LastDisassembleData.Bytes,4);
pdword(@LastDisassembleData.Bytes[0])^:=opcode;
address:=0;
x:=sizeof(opcode);
{$else}
x:=0;
setlength(LastDisassembleData.Bytes,4);
readprocessmemory(processhandle, pointer(address), @LastDisassembleData.Bytes[0], 4, x);
opcode:=pdword(@LastDisassembleData.Bytes[0])^;
{$endif}
LastDisassembleData.address:=address;
LastDisassembleData.SeperatorCount:=0;
LastDisassembleData.prefix:='';
LastDisassembleData.PrefixSize:=0;
LastDisassembleData.opcode:='';
LastDisassembleData.parameters:='';
lastdisassembledata.isjump:=false;
lastdisassembledata.iscall:=false;
lastdisassembledata.isret:=false;
lastdisassembledata.isconditionaljump:=false;
lastdisassembledata.modrmValueType:=dvtNone;
lastdisassembledata.parameterValueType:=dvtNone;
lastdisassembledata.Disassembler:=dcArm;
if (x=sizeof(opcode)) then
begin
if ((opcode shr 4) and $ffffff)=$12FFF1 then
BX
else
if (((opcode shr 2) and $3f)=0) and (((opcode shr 4) and $f)=$9) then
MUL
else
if (((opcode shr 23) and $1f)=2) and (((opcode shr 16) and $3f)=$f) and ((opcode and $FFF)=0) then
MRS
else
if (((opcode shr 23) and $1f)=2) and (((opcode shr 4) and $3FFFF)=$29F00) then
MSR
else
if (((opcode shr 23) and $3)=2) and (((opcode shr 26) and $3)=2) and (((opcode shr 12) and $3ff)=$28f) then
MSR_flg
else
if ((opcode shr 25) and %110)=%101 then
Branch
else
if (((opcode shr 26) and 3)=0) and (((opcode shr 4) and $f)<>9) then
DataProcessing
else
if (opcode shr 26) and 3=1 then
SingleDataTransfer
else
if (opcode shr 25) and %110=%100 then
LDM_STM
else
if ((opcode shr 23) and $1f=2) and ((opcode shr 20) and $3=0) and ((opcode shr 4) and $ff=9) then
SWP
else
if (opcode shr 24) and $F=$F then
SWI
else
if (((opcode shr 24) and $F)=$E) and (((opcode shr 4) and 1)=1) then
CDP
else
if (opcode shr 25) and $7f=$79 then
Advanced_SIMD_Data_Processing(LastDisassembleData);
//if (((opcode shr 24) and $f)=$E) and ((opcode shr 9) and $3=5) and ((opcode shr 4) and 1) = 1
end
else
LastDisassembleData.opcode:='??';
result:=inttohex(LastDisassembleData.address,8);
result:=result+' - ';
if x>0 then
begin
for i:=0 to length(LastDisassembleData.bytes)-1 do
result:=result+inttohex(LastDisassembleData.Bytes[i],2)+' ';
end
else
begin
for i:=0 to length(LastDisassembleData.bytes)-1 do
result:=result+'?? ';
end;
result:=result+' - ';
result:=result+LastDisassembleData.opcode;
result:=result+' ';
result:=result+LastDisassembleData.parameters;
inc(address,4);
end;
initialization
outputdebugstring('arm disassembler'); //runs
end.