1、函数的类型
叶子函数:函数内部没有调用其他函数:
void test1() {
int a = 2;
int b = 3;
}
非叶子函数:函数内部嵌套了其他函数:
void test2() {
int a = 4;
int b = 5;
test1();
}
2、函数的堆栈
2.1、叶子函数
sub sp, sp, #16
mov w8, #2
str w8, [sp, #12]
mov w8, #3
str w8, [sp, #8]
add sp, sp, #16
ret
代码分析:(假设执行test1函数前sp指针的值是0x10010) sub sp, sp, #16 ; sp = sp - 16,sp的地址值更新为0x10001,相当于开辟了16个字节的内存 mov w8, #2 ; 将2赋值给w8寄存器 str w8, [sp, #12] ; 将2存储到sp + 12地址中,也就是0x1000c开始的4个字节 mov w8, #3 ; 将3赋值给w8寄存器 str w8, [sp, #8] ; 将3存储到sp + 8地址中,也就是0x10008开始的4个字节 add sp, sp, #16 ; sp = sp + 16,sp的的值更新为0x10010,相当于释放16个字节的内存 ret ; 返回,将lr赋值给pc
2.2、非叶子函数
sub sp, sp, #32
stp x29, x30, [sp, #16]
add x29, sp, #16
mov w8, #4
stur w8, [x29, #-4]
mov w8, #5
str w8, [sp, #8]
bl _test1
ldp x29, x30, [sp, #16]
add sp, sp, #32
ret
代码分析:(假设执行test2函数前sp指针的值是0x10021) sub sp, sp, #32 ; sp = sp - 32,sp的地址值更新为0x10001,相当于开辟了32个字节的内存 stp x29, x30, [sp, #16] ; 将fp和lr存放到sp + 16开始的地址中,(保存lr是因为bl指令会更新lr) add x29, sp, #16 ; fp = sp + 16,sp和fp中间的16个字节空间就是函数留给局部变量使用的空间 mov w8, #4 ; 将4赋值给w8寄存器 stur w8, [x29, #-4] ; 将4保存到fp - 4, mov w8, #5 ; 将5赋值给w8寄存器 str w8, [sp, #8] ; 将5赋值给sp + 8 bl _test1 ; 跳转到test1函数,更新sp再复位sp ldp x29, x30, [sp, #16] ; 读取sp+16,将之前保存的fp和lr数据重新负值给fp和lr add sp, sp, #32 ; sp = sp + 32,恢复sp的位置,恢复堆栈平衡 ret ; 返回,将lr赋值给pc