Skip to content

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