vc++6.0中查看函数栈的结构
栈:一种后进先出的数据结构 比如:弹夹
函数调用的约定
传参顺序
传参媒介
如何传递返回值
平衡参数(堆栈平衡):有且只有被调方(callee)和调用方(caller)一方执行
_cdell (c约定,在C语言中 默认) <所有号称兼容C标准的编译器>
从右往左传参,通过栈传递参数,通过寄存器传递返回值,由被调方清除参数空间(平衡参数/堆栈/栈顶)
_stdcall (标准调用约定)
从右往左传参,通过栈传递参数,通过寄存器传递返回值,由调用方清除参数空间(平衡参数/堆栈/栈顶)
_fastcall <微软,非标准>
通过寄存器传递前两个参数,其余参数从右往左通过寄存器传递,通过寄存器传递返回值,由被调方清除参数空间
函数调用的步骤
1、按被调用约定传递参数
2、保存返回地址
3、流程转移到被调函数的首地址(第一条指令的地址)
4、保存调用方的栈信息(栈底)
5、更新当前栈信息(栈底),换句话说就是指定被调方的栈底位置
6、以局部变量总大小为依据,抬高栈底,也就是说为被调方的局部变量开辟空间
*6.1 在调试选项(/Od + /Zi)时,将局部变量初始化为0xcccccccc
7、保存寄存器环境
8、执行函数体
9、恢复寄存器环境
10、释放局部变量空间
11、恢复调用方的栈信息(栈底)
12A、_cdell约定时,直接取出返回地址,并按此地址回到被调方
12B、_stdcall 和_fastcall约定时,取出返回地址后,平衡参数多占用空间,按返回地址回到调用方
*13、_cdel约定时,调用方在此时平衡参数所占用空间
其中 * 代表可选项
现在我们到具体函数中分析
#include<stdio.h> #include<stdlib.h> int Sum(int a, int b) { int sum = 0; //system("pause"); sum = a + b; return sum; } int main() { int nNum1 = 3; int nNum2 = 5; Sum(nNum1, nNum2); system("pause"); return 0; }
在Ide环境中打开内存窗口,win7 32位 vc++6.0可以直接定位18ff40
接下来我们来具体分析了解如图所示
首先看看main函数的栈结构
接下来我们再看看sum函数的栈结构