记在最初,如果发现有专业术语的错误,请记得及时改正。 这个真的很重要。

1. 无参数传递的函数调用

本例会实际演示一个 只有函数局部变量赋值的demo
会先看一下C语言源代码和编译代码,然后一步一步的推演栈的空间使用

1.1 函数源码

C语言源码:

clipboard.png

注释: 这个脚本中,main 函数调用 f 函数,各自函数里面有局部变量的定义,函数调用没有参数传递。

编译代码:

clipboard.png

clipboard.png

汇编指令:

clipboard.png

1.2 编译step过程

0. 确认栈的地址

clipboard.png

为了方便记忆和观看,我们先假设栈的其实地址是 9000

1. 确定main函数的栈帧

clipboard.png

2. 保存局部变量

clipboard.png

如果变量 < 4 个,直接保存到寄存器。

变量数量 > 4 的部分放入到栈中。

具体的地址参数是

clipboard.png

3. 跳转到f函数

f 函数的第一步压栈处理

clipboard.png

4. 确认f函数的栈帧

clipboard.png

5. 返回参数变量

返回的值,会直接放到 r0 寄存器上

如果值比较大,会开辟一个地址单元,把地址返回给主函数

clipboard.png

6. 返回到main函数

clipboard.png

clipboard.png

然后直接返回

通过这样的操作,函数返回到 main 函数,上一个函数

7. 返回执行函数

可执行文件 使用 exec fork 子进程

main的上一个函数 是 execve

clipboard.png

把 execve 的地址 给 pC,下一条执行的 地址

clipboard.png

每个栈帧上一个函数的起始地址 比如 9000

bl b 指令自动会函数 下一条地址 压入栈

压栈的都是在下一级需要改变的,要不编译器会优化掉

2. 有传参的函数调用

2.1 运行实例代码

clipboard.png

对应的汇编代码

clipboard.png

2.2 执行步骤

1、main 函数压栈和入栈

clipboard.png

2. 存储局部变量

clipboard.png

3. 传参的入栈

clipboard.png

clipboard.png

4. 跳转到f函数

clipboard.png

5. f函数的压栈和入栈

clipboard.png

6. 传参在f函数的保存

clipboard.png

clipboard.png

初始化 sum 值

clipboard.png

7. f函数变量的赋值

clipboard.png

clipboard.png

可以发现此时改变的不是形参 n 而是 传参的栈地址

8. 加法运算

clipboard.png

clipboard.png

9. 返回main函数

clipboard.png

fp 返回的是栈帧保存的上一个函数的地址

然后重新回到了 main 函数

所以并没有改变实际参数的值,因为存储到不同的位置单元。 传参和定义的局部变量。 会保存栈或者寄存器的不同位置

3.形参和实参

结合上面 第二段的内容 形参和实参的分析
可以看出,在调用函数进行参数传递的时候,会重新分配栈空间或者寄存器进行管理。
而同时被调用的函数(比如f函数),在初始化中,会先把寄存器中的值取出来,放到自己的栈里面进行管理。

所以被传入的参数和main函数中的,属于不同的地址。因此也不会相互影响。

100. 致敬

如有不详,请参考王老师的精彩讲解 堆栈管理
学习过程中,获得了极大的满足感,把之前的一些东西串联了起来。十分感谢 王利涛老师
在此表示感谢。
PS:本文中所有的资源和图片均来自视频中


天真真不知路漫漫
70 声望6 粉丝

1