记在最初,如果发现有专业术语的错误,请记得及时改正。 这个真的很重要。
1. 无参数传递的函数调用
本例会实际演示一个 只有函数局部变量赋值的demo
会先看一下C语言源代码和编译代码,然后一步一步的推演栈的空间使用
1.1 函数源码
C语言源码:
注释: 这个脚本中,main 函数调用 f 函数,各自函数里面有局部变量的定义,函数调用没有参数传递。
编译代码:
汇编指令:
1.2 编译step过程
0. 确认栈的地址
为了方便记忆和观看,我们先假设栈的其实地址是 9000
1. 确定main函数的栈帧
2. 保存局部变量
如果变量 < 4 个,直接保存到寄存器。
变量数量 > 4 的部分放入到栈中。
具体的地址参数是
3. 跳转到f函数
f 函数的第一步压栈处理
4. 确认f函数的栈帧
5. 返回参数变量
返回的值,会直接放到 r0 寄存器上
如果值比较大,会开辟一个地址单元,把地址返回给主函数
6. 返回到main函数
然后直接返回
通过这样的操作,函数返回到 main 函数,上一个函数
7. 返回执行函数
可执行文件 使用 exec fork 子进程
main的上一个函数 是 execve
把 execve 的地址 给 pC,下一条执行的 地址
每个栈帧上一个函数的起始地址 比如 9000
bl b 指令自动会函数 下一条地址 压入栈
压栈的都是在下一级需要改变的,要不编译器会优化掉
2. 有传参的函数调用
2.1 运行实例代码
对应的汇编代码
2.2 执行步骤
1、main 函数压栈和入栈
2. 存储局部变量
3. 传参的入栈
4. 跳转到f函数
5. f函数的压栈和入栈
6. 传参在f函数的保存
初始化 sum 值
7. f函数变量的赋值
可以发现此时改变的不是形参 n 而是 传参的栈地址
8. 加法运算
9. 返回main函数
fp 返回的是栈帧保存的上一个函数的地址
然后重新回到了 main 函数
所以并没有改变实际参数的值,因为存储到不同的位置单元。 传参和定义的局部变量。 会保存栈或者寄存器的不同位置
3.形参和实参
结合上面 第二段的内容 形参和实参的分析
可以看出,在调用函数进行参数传递的时候,会重新分配栈空间或者寄存器进行管理。
而同时被调用的函数(比如f函数),在初始化中,会先把寄存器中的值取出来,放到自己的栈里面进行管理。
所以被传入的参数和main函数中的,属于不同的地址。因此也不会相互影响。
100. 致敬
如有不详,请参考王老师的精彩讲解 堆栈管理
学习过程中,获得了极大的满足感,把之前的一些东西串联了起来。十分感谢 王利涛老师。
在此表示感谢。
PS:本文中所有的资源和图片均来自视频中
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。