我们知道每次函数调用都是一个过程,这个过程称之为函数的调用过程。且每次函数调用都要为本次函数调用开辟栈空间,
用于本次函数的调用中临时变量的保存、现场保护。这块栈空间我们称之为函数栈帧。
那又怎样维护这块空间呢?这块空间的上限在哪里、下限又在哪里?
这里就涉及两个寄存器(ebp和esp),在函数的调用过程中这两个寄存器存放了维护这个栈的栈低和栈顶指针。
ebp存放了指向函数栈帧栈底的地址。
esp存放了指向函数栈帧栈顶的地址。
注:栈空间的使用是由高地址向底地址,所以越是低的地址越是靠后入栈
现在深入的研究一下函数的调用过程
先看下面这段代码:
当进行程序调试的时候,查看【函数堆栈】,会出现如下:
由此,我们可以发现main函数在__tmainCRTStartup函数中调用,而__tmainCRTStartup函数在mainCRTStartup函数中被调用。
当我们详细研究函数的栈帧调用,必须对应反汇编代码
1. 从main函数开始,先来看main函数栈帧的创建
2. 接下来是add函数的调用
参数传递过程
这里需要注意的是call指令的调用。
执 行call指令时按F11,来到这里,
再按F11就进入Add函数的执行代码处
这里需要注意返回结果保存在eax寄存器中,
再然后,就是函数的返回部分
这里需要注意ret指令,
整个过程的图解如下,
例题:
利用上面的知识,看一下在VC6.0环境中,下面代码的结果是什么?
结果为:20
原因:仿照上面函数的调用过程,不难理解,*(&tmp+1)正好为main函数的栈低地址,即p为(main-esp),整形指针加(或减)1,跳过4个字节,则p-1为a变量空间地址,即*(p-1)=20,改变了a变量的值,所以输出结果为20.