本文的主要目的是理解函数栈
以及涉及的相关指令
在讲函数的本质之前,首先需要讲下以下几个概念栈、SP、FP
常识
栈
- 栈:是一种
具有特殊的访问方式的存储空间
(即先进后出 Last In Out First,LIFO
)
- 高地址往低地址存数据(
存:高-->低
)
- 栈空间开辟:往低地址开辟(`开辟:高-->低`)
复制代码
SP和FP寄存器
-
SP寄存器
:在任意时刻会保存栈顶的地址
-
FP寄存器
(也称为x29
寄存器):属于通用寄存器,但是在某些时刻(例如函数嵌套调用时)可以利用它保存栈底的地址
注意:
arm64开始,取消了32位的LDM、STM、PUSH、POP指令,取而代之的是
ldr/ldp、str/stp
(r和p的区别在于处理的寄存器个数,r表示处理1个寄存器,p表示处理两个寄存器)arm64中,对栈的操作是
16字节对齐
的!!!
以下是arm64之前和arm64之后的一个对比 !
-
在arm64之前,栈顶指针是压栈时一个数据移动一个单元
-
在arm64开始,首先是
从高地址往低地址开辟一段栈空间(由编译器决定)
,然后再放入数据,所以不存在push、pop操作。这种情况可以通过内存读写指令(ldr/ldp、str/stp
)对其进行操作
函数调用栈
以下是常见的函数调用开辟 (sub)
以及恢复栈空间 (add)
的汇编代码
//开辟栈空间
sub sp, sp, #0x40 ; 拉伸0x40(64字节)空间
stp x29, x30, [sp, #0x30] ;x29\x30 寄存器入栈保护
add x29, sp, #0x30 ; x29指向栈帧的底部
...
ldp x29, x30, [sp, #0x30] ;恢复x29/x30 寄存器的值
//恢复栈空间
add sp, sp, #0x40 ; 栈平衡
ret
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发交流群:130595548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)
内存读写指令
-
str(store register)指令
(能和内存和寄存器交互的专门的指令):将数据从寄存器中读出来,存到内存中 (即一个寄存器是8字节-64位
) -
ldr(load register)指令
:将数据从内存中读出来,存到寄存器中 -
此时ldr和str的变种
ldp和stp
还可以操作2个
寄存器(即128位-16字节
)
注意:
读/写数据都是往
高地址
读/写写数据:先拉伸栈空间,再拿sp进行写数据,即
先申请空间再写数据
练习
使用32个字节空间作为