C语言 函数的调用过程(栈帧)
函数的调用过程叫栈帧,那么栈区在哪??看下图:
为了帮助理解,下面会涉及到代码的调试以及部分的汇编语言。
代码:
打开调试窗口中的 调试堆栈,我们不难看出,main()函数正在被其他函数调用,也就是说我们通常意义上讲的,main()函数是第一个被调用的函数的说法是不严谨的,在程序运行起来之后,main函数会被mainCRTsetup()函数调用,但是main()是我们代码的逻辑入口。
栈帧的维护必须用到ebp esp寄存器:
我们知道,栈在存储过程中是向下生长的,寄存器在cpu中,ebp指向栈帧的栈底,esp指向栈帧的栈顶
接下来,是main函数在栈中开辟的栈帧空间
继续调试,接着看汇编代码,下面是Add函数的调用,此时call指令下一条指令的地址存储在了cpu寄存器eip中
接下来,根据call指令跳进Add函数内部
接下来是返回的部分,对应汇编指令pop
ret指令:ret指令会使得出栈一次,并将出栈的内容当做地址,将程序执行跳转到该地址处。
call指令:汇编语言中CALL指令调用一个子程序,CPU执行call指令,进行两步操作:
(1)将当前的 IP 压入栈中;
(2)转移到紧跟的标号行地址执行程序。
总结:学习函数的栈帧,可以帮助我们理解代码在运行过程中,保存在内存的哪个区域(栈),何时保存(调用过程进行压栈),保存的顺序是什么(定义参数时顺序保存,形成形参时在栈中逆向压栈),有助于我们理解接下来更为复杂的函数,即使我们并不知道函数的功能是什么,但是我们依旧可以分析出他们的原理,从原理出发,理解起来就不会觉得无从下手。