如果能理解函数栈帧的创建与销毁 可以大大提高我们理解c语言其他知识点的能力
接下来我用vs2019的环境给大家简单讲解一下函数栈帧的创建与销毁
因为会用到汇编 所以先给大家介绍几个汇编指令和要用到的寄存器
大家要注意的是栈区使用规则是先使用高地址 在使用低地址
在本文章中 下面是高地址 上面是低地址
用一段及其简单的调用函数来调试这个过程
要注意的是有其他函数来调用main函数
当我们运行程序我们转到反汇编
上来就是三个压栈 注意压栈的同时esp也会变动
下面看到的指令就是数据的创建过程
调用add之前 这个过程其实就是传参
把ebp-14h的值给eax把eax压入栈顶
把ebp-8的值给ecx把ecx压入栈顶
ebp-14h是什么?ebp-8是什么?恰好就是我们创建的变量a和b
注意的是 我们是先压的b后压的a 这个和我们的函数传参有关 是从右向左依次压栈
然后是call指令
注意call指令存的是返回main函数时 继续执行的语句的地址
call执行时会压入返回地址 并进入目标函数
此时我们已经进入了MyAdd函数
在栈顶压入一个ebp 注意此时ebp里的值就是main函数的ebp
然后在把esp的值移动给ebp 并且让esp - 0cch
继续压栈
这段指令我不多做解释就是一个初始化的过程把这段内存的值全部变成ccccccc
这就是有时我们打印出烫烫烫烫烫烫烫烫的原因
看我们是怎么使用传参变量的
把ebp+8的值放进eax里
在用eax加上ebp+0ch
注意看是不是我们进入add函数之前压进去的 同过ebp加减来寻找这个地址
但是注意的事把这个值存在了eax寄存器里
在看mov的指令 把eax的值给ebp - 8
当然上面的代码还是不够详细
如果是先创建一个int z=0;
z=x+y; 就会比这个详细 但道理是一样的
此时我们已经完成加法 但是还没有返回
我们开始弹栈
add,0cch 记得我们之前创建时是sub,0cch
也就是把esp的位置还回去了
mov 把ebp的值放进esp里
然后把ebp pop掉
ret 恢复返回地址 注意的是现在存的 是不是就是之前main函数的ebp
恢复之后ebp 就回到了main最开始的ebp那个位置
ret还要压出一个值
add esp+8
也就把esi和ebx pop掉了
然后才开始接受返回的值
大家看到这还记得 我们之前把加完的值存入了eax里
mov指令 把eax的值移动给ebp-20h
这就是一个函数栈帧的创建和销毁了
接下来我们总结一下
1.调用函数,需要先形成临时拷贝,形成过程是从右向左的
2.临时空间的开辟,是在对应的栈帧里内部开辟的
3.函数调用 完毕,函数的栈帧会被销毁
4.临时变量具有临时性的本质是因为函数栈帧存在临时性
5.函数调用时有成本的,体现在时间和空间上,本质是因为调用函数时创建栈帧和销毁栈帧有成本
6函数调用,因拷贝形成的临时变量,位置是挨着放的 有规律的
大家觉得有收获的话点个赞吧