ARM64 PCS(procedure Call Stanard)定义:
X29 is the frame pointer register (FP). 用来定位有效的栈帧记录。
X30 is the link register (LR). The branch-and-link instructions that store a return address in the link register (BL and BLR), setting the register X30 to PC+4. Calls to subroutines, where it is necessary for the return address to be stored in the link register(X30).
link register for subroutine calls is different to the link register for exceptions.
从上图中可以看到一个有效栈帧通用的布局,
“Local variables + callee saved register + 上一栈帧的LR`/FP`”
首先来看一下load和store指令有关的几种寻址模式, 这会帮助理解后面的汇编代码。
Base
register:
Offset addressing modes:
Pre-index addressing modes:
Post-index addressing modes:
从实例中看这两个寄存器是如何起作用的.
我们是否可以修改x30寄存器???
写一个汇编代码来定义trampoline_test(),函数返回值为8;
$cat stack_frame.S
#include
#include
#include
.text
.global trampoline_test trampoline_test: stp x29, x30, [sp, #-16]! mov x29, sp stp x19, x20, [sp, #-16]! stp x21, x22, [sp, #-16]! stp x25, x26, [sp, #-16]! mov x25, sp mov x26, #0x0 mov w7, #0x0 ldp x25, x26, [sp], #16 ldp x21, x22, [sp], #16 ldp x19, x20, [sp], #16 ldp x29, x30, [sp], #16 add x0, x7, #0x8 // return 8; ret |
下面代码执行后,输出为: 208
i = trampoline_test(); i = 200; i += 8;
printf("i==%d\n",i); |
编译执行:
as -o stack_frame.o stack_frame.S gcc -c -o jump_test.o jump_test.c gcc jump_test.o stack_frame.o -o jump_test |
|
将代码稍微改动,ret之前将x30值 +8;
$cat stack_frame.S
#include
#include
#include
.text
.global trampoline_test trampoline_test: stp x29, x30, [sp, #-16]! mov x29, sp stp x19, x20, [sp, #-16]! stp x21, x22, [sp, #-16]! stp x25, x26, [sp, #-16]! mov x25, sp mov x26, #0x0 mov w7, #0x0 ldp x25, x26, [sp], #16 ldp x21, x22, [sp], #16 ldp x19, x20, [sp], #16 ldp x29, x30, [sp], #16 add x0, x7, #0x8 // return 8; add x30, x30, #0x8 // 跳过两条指令 ret |
再次编译执行:
从反汇编代码中看到“add x30, x30, #0x8”正是跳过了“i = 200;”这条语句;
所以最终的执行结果为 i==16.