-
Notifications
You must be signed in to change notification settings - Fork 10
AArch64
Mahdi Safsafi edited this page Aug 24, 2017
·
1 revision
The example bellow shows how to use Azote to decode opcode.
var
Insn:TA64Instruction;
begin
FillChar(Insn, SizeOf(TA64Instruction), #00);
Insn.OpCode := OpCode;
if(DecodeInstruction(Insn))then
begin
// Do something with Insn here.
end;
end;
Before calling DecodeInstruction
function, it's necessary to initialize the Insn
structure to 0. After initialization, you set your opcode that you want to decode and optionally set decoding options. After decoding opcode, Insn
will be filled with valid information that applies to that opcode.
TA64Instruction = record
/// <summary>Instruction identifier (ID).</summary>
IID: TA64InstructionIID;
/// <summary>Instruction opcode value.</summary>
OpCode: UInt32;
/// <summary>Instruction conditional execution.</summary>
Condition: TA64Condition;
/// <summary>Instruction class.</summary>
IClass: TA64Class;
/// <summary>Instruction syntax.</summary>
Syntax: AnsiString;
/// <summary>Number of operand.</summary>
OperandCount: Integer;
/// <summary>A list of operand used by the instruction.</summary>
Operands: array [0 .. { OperandCount } A64_MAX_OPERANDS - 1] of TA64Operand;
Options: TAzoteOptions;
/// <summary>Storable field.</summary>
/// <para>This field is only used during the process.
/// You can store here what you want.
/// </para>
case Boolean of
True: (UserTag: NativeInt);
False: (Internal: Pointer);
end;
- IID: Instruction ID that allows to us to distinguish between instructions.
if(Insn.IID = INSN_ADD) then
// It's add instruction.
else if(Insn.IID = INSN_MOV) then
// It's mov instruction.
// and so on ...
- OpCode: The opcode that you want to decode.
- Condition: Instruction conditional execution.
if (Insn.Condition = cdEQ) then
// The instruction executes only when (Z = 1).
- IClass: Instruction class.
- Syntax: Instruction syntax (string).
- OperandCount: Number of operand used by the instruction.
-
Operands: An
array [0 .. OperandCount -1] of operand
representing instruction arguments. -
Options: Options for decoding.
- optLittleEndian: By default, Azote assumes that
OpCode
you provided is Big-Endian. If your opcode's endianness is Little-Endian, you need to specify that by includingoptLittleEndian
inInsn.Options
.
- optLittleEndian: By default, Azote assumes that
- UserTag: Here's your space, you can store what you want here.
You should carefully access operand info. Because they are structured in union. Only access info if OperandType and Flags indicate that info is valid.
TA64Operand = record
/// <summary>Argument Index.</summary>
ID: Integer;
/// <summary>Argument flags.</summary>
Flags: TOperandFlags;
/// <summary>Argument type.</summary>
/// <para>Accessing operand info depends on OperandType and Flags.</para>
OperandType: TOperandType;
case TOperandType { OperandType } of
otList: (List: TA64ListInfo);
otCondition: (Condition: TA64Condition);
otRegister: (Register: TA64Register);
otLabel: (RelOffset: Int64);
otMemory: (Memory: TA64MemoryInfo);
otHint: (Hint: TA64HintOption);
otImmediate: (Immediate: TA64ImmediateInfo;
case TOperandFlag { Flags } of
ofArrangement: (Arrangement: TA64Arrangement; Index: Integer);
ofShifter: (Shifter: TA64Shifter; Amount: Integer);
);
end;
- ID: Operand index.
-
Flags: Operand flags. It could be a combination of:
- ofShifter: Operand has a shifter. Shifter and Amount info are valid.
- ofArrangement: Operand has arrangement. Arrangement info is valid. And Index is valid only
if(Index > -1)
. - ofDestination: Operand will be modified after executing the instruction.
- OperandType: indicates operand type (register, immediate, list, memory, ...).
{ This example demonstrates how to find all 'Add/Sub' instructions }
const
OpCodes: array [0 .. 7] of UInt32 = (
$8B348331, // add x17, x25, w20, sxtb.
$B203295F, // orr sp, x10, #0xe00000ffe00000ff.
$0B33A23A, // add w26, w17, w19, sxth.
$CB250882, // sub x2, x4, w5, uxtb #2.
$CB3333F4, // sub x20, sp, w19, uxth #4.
$8B23C05F, // add sp, x2, w3, sxtw.
$4B23C05F, // sub wsp, w2, w3, sxtw.
$AB3333FF // cmn sp, w19, uxth #4.
);
var
Insn: TA64Instruction;
I: Integer;
begin
try
Writeln('Add/Sub Instructions:');
for I := 0 to Length(OpCodes) - 1 do
begin
FillChar(Insn, SizeOf(TA64Instruction), #00);
Insn.OpCode := OpCodes[I];
if (DecodeInstruction(Insn)) then
begin
if (Insn.IID = INSN_ADD) or (Insn.IID = INSN_SUB) then
begin
Writeln(Insn.Syntax);
end;
end;
end;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Output:
Add/Sub Instructions:
add x17, x25, w20, sxtb
add w26, w17, w19, sxth
sub x2, x4, w5, uxtb #2
sub x20, sp, w19, uxth #4
add sp, x2, w3, sxtw
sub wsp, w2, w3, sxtw
{ This example demonstrates how to find all instructions
that may change the stack pointer register value. }
const
OpCodes: array [0 .. 7] of UInt32 = (
$8B348331, // add x17, x25, w20, sxtb.
$B203295F, // orr sp, x10, #0xe00000ffe00000ff.
$0B33A23A, // add w26, w17, w19, sxth.
$CB250882, // sub x2, x4, w5, uxtb #2.
$CB3333F4, // sub x20, sp, w19, uxth #4.
$8B23C05F, // add sp, x2, w3, sxtw.
$4B23C05F, // sub wsp, w2, w3, sxtw.
$AB3333FF // cmn sp, w19, uxth #4.
);
var
Insn: TA64Instruction;
I: Integer;
J: Integer;
Operand: TA64Operand;
begin
try
Writeln('Instructions that modify stack pointer register are:');
for I := 0 to Length(OpCodes) - 1 do
begin
FillChar(Insn, SizeOf(TA64Instruction), #00);
Insn.OpCode := OpCodes[I];
if (DecodeInstruction(Insn)) then
begin
{ Iterate through instruction operands. }
for J := 0 to Insn.OperandCount - 1 do
begin
Operand := Insn.Operands[J];
if ((Operand.OperandType = otRegister) and (ofDestination in Operand.Flags { register is not source. } ) and
((Operand.Register = REG_SP) or (Operand.Register = REG_WSP))) then
begin
Writeln(Insn.Syntax);
Break;
end;
end;
end;
end;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Output:
Instructions that modify stack pointer register are:
orr sp, x10, #-2305841910238936833
add sp, x2, w3, sxtw
sub wsp, w2, w3, sxtw