Operations
This page provides a reference for all of the various 'operations' implemented by individual JIT(s).
For more information about each of the operations, see the source code 😉 (enum Operation<T>
).
Needed for Basic Hooking Support
JumpRelative
Represents jumping to a relative offset from current instruction pointer.
let jump_rel = JumpRelativeOperation {
target_address: 0x200,
};
jmp 0x200 ; Jump to address at current IP + 0x200
b 0x200 ; Branch to address at current IP + 0x200
adrp x9, #0 ; Load 4K page, relative to PC. (round address down to 4096)
add x9, x9, #100 ; Add any missing offset.
blr x9 ; Branch to location
jmp 0x200 ; Jump to address at current IP + 0x200
JumpAbsolute
Represents jumping to an absolute address stored in a register.
JIT is free to encode this as a relative branch if it's possible.
let jump_abs = JumpAbsoluteOperation {
scratch_register: rax,
target_address: 0x123456,
};
mov rax, 0x123456 ; Move target address into rax
jmp rax ; Jump to address in rax
MOVZ x9, #0x3456 ; Set lower bits.
MOVK x9, #0x12, LSL #16 ; Move upper bits
br x9 ; Branch to location
mov eax, 0x123456 ; Move target address into eax
jmp eax ; Jump to address in eax
We prefer this approach to absolute jump
because it is faster performance wise.
JumpAbsoluteIndirect
Represents jumping to an absolute address stored in a memory address.
let jump_ind = JumpIndirectOperation {
target_address: 0x123456,
};
jmp qword [0x123456] ; Jump to address stored at 0x123456
jmp dword [0x123456] ; Jump to address stored at 0x123456
; Possible on Multiple of 0x10000 with offset 0-4096
MOVZ x9, #0x123, LSL #16 ; Store upper 16 bits.
LDR x9, [x9, #0x456] ; Load lower 12 bit offset
br x9 ; Branch to location
; On any address up to 4GiB + 4096
MOVZ x9, #0x3456 ; Set lower bits.
MOVK x9, #0x12, LSL #16 ; Move upper bits
; Continue until desired address.
LDR x9, [x9, #0x0] ; Load from address.
br x9
- Values in brackets indicate max address usable.
On MacOS, this is not usable, because memory < 2GiB is restricted from access.
Needed for Wrapper Generation
This includes functionality like 'parameter injection'.
Mov
Represents a move operation between two registers.
let move_op = MovOperation {
source: r8,
target: r9,
};
mov r9, r8 ; Move r8 into r9
mov x9, x8 ; Move x8 into x9
mov ebx, eax ; Move eax into ebx
MovFromStack
Represents a move operation from the stack into a register.
let move_from_stack = MovFromStackOperation {
stack_offset: 8,
target: rbx,
};
mov rbx, [rsp + 8] ; Move value at rsp + 8 into rbx
ldr x9, [sp, #8] ; Load value at sp + 8 into x9
mov ebx, [esp + 8] ; Move value at esp + 8 into ebx
MovToStack
Represents moving a register value onto the stack at a user specified offset.
let mov_to_stack = MovToStackOperation {
register: rbx,
stack_offset: 16,
};
mov [rsp + 16], rbx ; Move rbx onto the stack 16 bytes above rsp
str x9, [sp, #16] ; Store x9 onto the stack 16 bytes above sp
mov [esp + 16], ebx ; Move ebx onto the stack 16 bytes above esp
Push
Represents pushing a register onto the stack.
let push = PushOperation {
register: r9,
};
push r9 ; Push rbx onto the stack
sub sp, sp, #8 ; Decrement stack pointer
str x9, [sp] ; Store x9 on the stack
push ebx ; Push ebx onto the stack
PushStack
Represents pushing a value from the stack to the stack.
let push_stack = PushStackOperation {
offset: 8,
item_size: 8,
};
push qword [rsp + 8] ; Push value at rsp + 8 onto the stack
ldr x9, [sp, #8] ; Load value at sp + 8 into x9
sub sp, sp, #8 ; Decrement stack pointer
str x9, [sp] ; Push x9 onto the stack
push [esp + 8] ; Push value at esp + 8 onto the stack
PushConstant
Represents pushing a constant value onto the stack.
let push_const = PushConstantOperation {
value: 10,
};
push 10 ; Push constant value 10 onto stack
sub sp, sp, #8 ; Decrement stack pointer
mov x9, 10 ; Move constant 10 into x9
str x9, [sp] ; Store x9 on the stack
push 10 ; Push constant value 10 onto stack
StackAlloc
Represents adjusting the stack pointer.
let stack_alloc = StackAllocOperation {
operand: 8,
};
sub rsp, 8 ; Decrement rsp by 8
sub sp, sp, #8 ; Decrement sp by 8
sub esp, 8 ; Decrement esp by 8
Pop
Represents popping a value from the stack into a register.
let pop = PopOperation {
register: rbx,
};
pop rbx ; Pop value from stack into rbx
ldr x9, [sp] ; Load stack top into x9
add sp, sp, #8 ; Increment stack pointer
pop ebx ; Pop value from stack into ebx
XChg
Represents exchanging the contents of two registers.
On some architectures (e.g. ARM64) this requires a scratch register.
let xchg = XChgOperation {
register1: r9,
register2: r8,
scratch: None,
};
xchg r8, r9 ; Swap r8 and r9
// ARM doesn't have xchg instruction
mov x10, x8 ; Move x8 into x10 (scratch register)
mov x8, x9 ; Move x9 into x8
mov x9, x10 ; Move original x8 (in x10) into x9
xchg eax, ebx ; Swap eax and ebx
CallAbsolute
Represents calling an absolute address stored in a register or memory.
let call_abs = CallAbsoluteOperation {
scratch_register: r9,
target_address: 0x123456,
};
mov rax, 0x123456 ; Move target address into rax
call r9 ; Call address in rax
adr x9, target_func ; Load address of target function into x9
blr x9 ; Branch and link to address in x9
mov eax, 0x123456 ; Move target address into eax
call eax ; Call address in eax
CallRelative
Represents calling a relative offset from current instruction pointer.
let call_rel = CallRelativeOperation {
target_address: 0x200,
};
call 0x200 ; Call address at current IP + 0x200
bl 0x200 ; Branch with link to address at current IP + 0x200
call 0x200 ; Call address at current IP + 0x200
Return
Represents returning from a function call.
let ret = ReturnOperation {
offset: 4,
};
ret ; Return
ret 4 ; Return and add 4 to stack pointer
ret ; Return
add sp, sp, #4 ; Add 4 to stack pointer
ret ; Return
ret ; Return
ret 4 ; Return and add 4 to stack pointer
Architecture Specific Operations
These operations are only available on certain architectures.
These are non essential, but can improve compatibility/performance.
Enabled by setting JitCapabilities::CanEncodeIPRelativeCall
and JitCapabilities::CanEncodeIPRelativeJump
in JIT.
CallIpRelative
Represents calling an IP-relative offset where target address is stored.
let call_rip_rel = CallIpRelativeOperation {
target_address: 0x1000,
};
call qword [rip - 16] ; Address 0x1000 is at RIP-16 and contains raw address to call
ldr x9, 4 ; Read item in a multiple of 4 bytes relative to PC
blr x9 ; Branch call to location
adrp x9, #0x0 ; Load 4K page, relative to PC. (round address down to 4096)
ldr x9, [x9, 1110] ; Read address from offset in 4K page.
blr x9 ; Branch to location
JumpIpRelative
Represents jumping to an IP-relative offset where target address is stored.
let jump_rip_rel = JumpIpRelativeOperation {
target_address: 0x1000,
};
jmp qword [rip - 16] ; Address 0x1000 is at RIP-16 and contains raw address to jump
ldr x9, 4 ; Read item in a multiple of 4 bytes relative to PC
br x9 ; Branch call to location
adrp x9, #0x0 ; Load 4K page, relative to PC. (round address down to 4096)
ldr x9, [x9, 1110] ; Read address from offset in 4K page.
br x9 ; Branch call to location
Optimized Push/Pop Operations
Enabled by setting JitCapabilities::CanMultiPush
in JIT.
MultiPush
Represents pushing multiple registers onto the stack.
Implementations must support push/pop of mixed registers (e.g. Reg+Vector).
let multi_push = MultiPushOperation {
registers: [
PushOperation { register: rbx },
PushOperation { register: rax },
PushOperation { register: rcx },
PushOperation { register: rdx },
],
};
push rbx
push rax
push rcx
push rdx ; Push rbx, rax, rcx, rdx onto the stack
sub sp, sp, #32 ; Decrement stack pointer by 32 bytes
stp x9, x8, [sp] ; Store x9 and x8 on the stack
stp x11, x10, [sp, #16] ; Store x11 and x10 on the stack
push ebx
push eax
push ecx
push edx ; Push ebx, eax, ecx, edx onto the stack
MultiPop
Represents popping multiple registers from the stack.
Implementations must support push/pop of mixed registers (e.g. Reg+Vector).
let multi_pop = MultiPopOperation {
registers: [
PopOperation { register: rdx },
PopOperation { register: rcx },
PopOperation { register: rax },
PopOperation { register: rbx },
],
};
pop rdx
pop rcx
pop rax
pop rbx ; Pop rdx, rcx, rax, rbx from the stack
ldp x11, x10, [sp], #16 ; Load x11 and x10 from stack and update stack pointer
ldp x9, x8, [sp], #16 ; Load x9 and x8 from stack and update stack pointer
pop edx
pop ecx
pop eax
pop ebx ; Pop edx, ecx, eax, ebx from the stack