-
雷迪斯俺的枕头们。小谷又来学习了~ 今天说一波比较常用--
函数
~ -
兄弟们都听说过
函数调用栈
,今天就从汇编
层次简单的理解下函数
~
1. 栈
1.1. 栈的概念
-
函数调用栈
的栈
,不是通常所说的说的数据结构
,这个栈指的是拥有特殊访问能力的存储空间
(FILO:first in last out,先进后出
) -
来一波图(我比较喜欢偷图,就离谱😆)
1.2. 栈的关键点
-
- 现在
arm64
,已经弱化了栈
的形式,没有32位的(push,pop
)操作了
- 现在
-
- 在
iOS开发
中,栈是由高地址
走向低地址
存储
- 在
-
- 在
iOS开发
中。sp(栈顶指针)
指向存储是向高地址
的
- 在
-
- 小谷画了一波图~(这个图是我画的)
1.3. SP和FP寄存器
上面那个图画的时候用的了
sp
,下面解释一下
-
SP寄存器
:一直保存栈顶的地址 -
FP寄存器
:有些时候需要他保存着栈底的地址,也是X29寄存器。
注:
arm64
架构,对栈的操作是16字节对齐
的
1.4. 函数调用栈
- 兄弟们应该都听说过
函数调用栈
,我们简单写一个函数
看一波
简单函数调用
- 常见的函数调用和开辟空间~
- ";"代表注释~
StackFuncDemo`stackFuncTest:
-> 0x102afa20c <+0>: stp x29, x30, [sp, #-0x10]!;首先将sp(栈顶指针)向低地址拉伸0x10,”!”代表拉伸完偏移sp,之后取地址,存储x29,x30寄存器
0x102afa210 <+4>: mov x29, sp ;将sp(栈顶指针)存储的值压入x29
0x102afa214 <+8>: adrp x0, 1
0x102afa218 <+12>: add x0, x0, #0xf69 ; =0xf69
0x102afa21c <+16>: bl 0x102afa5ac ; symbol stub for: printf
0x102afa220 <+20>: ldp x29, x30, [sp], #0x10 ;将sp(栈顶指针)所在地址取值给x29,x30,然后在向高地址回放0x10,(栈平衡)
0x102afa224 <+24>: ret ;返回
这里面的倒数第二句,为什么要把
sp
所在地址的值重新赋值给x29,x30
?,难道bl
指令的时候,这其中寄存器发生改变了?
2. bl和ret指令
2.1. bl指令
-
- 上面我们看到了,
bl
操作过好像会发生改变。耐不住寂寞的我必须要来观察一波了
- 上面我们看到了,
-
- 不知道大家是否和我一样:我马上去查了下
bl指令
- 不知道大家是否和我一样:我马上去查了下
将下一条指令的地址放入
lr(x30)
寄存器
跳转到标号处执行指令
-
- 那我们观察下是否是
lr(x30)
寄存器调用bl
之后发生改变就好了~
- 那我们观察下是否是
-
- 简单写个函数嵌套调用
void test2(){
}
void test1(){
test2();
}
int main(int argc, char * argv[]) {
printf("test-now\n");
// stackFuncTest();
test1();
printf("test--end\n”);
}
-
- 断点看汇编~
我们证明了上面的问题,
通过bl指令的确会是x30寄存器(别名:lr)发生改变
2.2. ret 指令
-
ret
指令其实就是返回
的意思 -
ret
指令是跳转到x30寄存器
里面所指向的地址
~