首先说一下函数栈帧的定义:在每一次调用函数时,为该函数开辟的,用于本次函数调用中变量的保存、现场保护的空间称为函数栈帧。
为了进一步了解函数栈帧,我们先来对下面这段代码进行调试:
通过调试,我们会发现,程序在运行过程中,首先会为main函数开辟一段空间,当代码走到调用Add函数这一步时,便会为Add函数开辟一段合理的空间。而且不仅仅只有main函数,main函数是被_tmainCRTStartup函数调用的,而_tmainCRTStartup函数则是被mainCRTStartup函数调用。
在函数栈帧中有两个非常重要的寄存器:
1. ebp:用于存放指向当前函数栈帧栈底的地址。
2. esp:用于维护栈顶,存放指向当前函数栈帧栈顶的地址,每当完成一次push操作,esp的地址就会更新为当前栈顶。
知道了这两个寄存器的含义之后,我们再来对上述这段代码所对应的汇编代码进行分析:
在执行到call指令时,按F11,执行 jmp 指令,进行地址的跳转:
我们可以看到,通过 jmp 指令的跳转,刚好来到了Add函数的内部,而且Add函数的栈帧与main函数栈帧的整体思路是相同的。剩下的就是函数的返回部分,根据之前压栈的顺序出栈。
ret指令会使得出栈一次,并将出栈的内容当作地址,将程序跳转到该地址处。
根据上述分析,总结函数调用压栈顺序,可以得出如下图:
通过对一个简单代码的分析,我们可以进一步了解程序运行时,函数调用栈的过程,明白其中原理。
以上只是我对函数栈帧的粗浅理解、分析,有什么不足之处,还望各位大佬看过之后,指出我的不足,有什么可以探讨的点,我们也可以共同谈论,相互学习。