函数调用
x29: fp (栈底,高地址) sp: (栈顶,低地址) x30: lr(返回地址) 调用函数: bl 地址,x30 = pc + 4 函数开头:
SUB SP, SP, stack_size
STP X29, X30, [SP,stack_size-0x10+var_s0] // store pair
ADD X29, SP, stack_size-0x10
结尾:
LDP X29, X30, [SP,stack_size-0x10+var_s0] // load pair
ADD SP, SP, stack_size
RET
调用约定:
参数、返回值寄存器传递,x0~x7
, f0~f7
x8 (xr) 是一个间接结果寄存器。系统调用编号。
x9 到 x15 是调用者保存的临时寄存器。
x16 (ip0) and x17 (ip1) are inter-procedural scratch registers. Meaning they are used as scratch registers only during a Prologue. Other than that, they basically are never used.
x18 (pr) is known as the platform register. Basically just another scratch register. Rarely used.
x19 至 x28 是被调用者保存的寄存器。
f8 至 f15 是被调用者保存的寄存器(类似于 x19 至 x28)
f16 至 f31 是临时寄存器,处理方式类似于 x9 至 x15。
保存现场
将代码插入程序(例如漏洞或某些视频游戏作弊码)时,有一个简单的方法可以安全地使用非易失性寄存器,同时还包括修改“永不安全”的 sp 寄存器。
Place this at the start of your exploit/cheat…
stp fp, lr, [sp, #-0x60]!
stp x19, x20, [sp, #0x10]
stp x21, x22, [sp, #0x20]
stp x23, x24, [sp, #0x30]
stp x25, x26, [sp, #0x40]
stp x27, x28, [sp, #0x50]
mov fp, sp
And place this at the end of your exploit/cheat…
ldp x27, x28, [sp, #0x50]
ldp x25, x26, [sp, #0x40]
ldp x23, x24, [sp, #0x30]
ldp x21, x22, [sp, #0x20]
ldp x19, x20, [sp, #0x10]
ldp fp, lr, [sp], #0x60
This will allow you to use any of the non-volatile registers you desire.
内联汇编示例
#include <cstdio>
int main() {
int a=10, b;
// ...
asm volatile (
R"(
mov w0, %w0
mov w1, #0x20
add %w0, w0, w1
)"
// ... some other operations
: "=r"(b)/* no outputs */
: "r"(a)/* no inputs */
: "x0", "x1", "memory" // 告知编译器x0和x1寄存器的值已被修改
);
printf("%d\n", b);
// ...
}