函数调用时堆栈是如何分配的

函数调用时堆栈是如何分配的?使用VC2005在i386系列机器上进行试验,发现与编译选项有很大的关系。使用cl.exe不加任何选项直接编译,结果大致如下

高地址

函数调用堆栈
高地址传入参数
 返回地址
 调用函数的EBP值
 局部变量
 局部变量数组
 。。。(标注1)
低地址 

小结

1)传入参数的入栈顺序与调用约定有关,_cdecl和_stdcall这两种调用约定都是从右至左入栈。

2)如果函数中定义了局部变量数组,无论数组声明的位置如何,总是被分配到栈顶位置,即被分配在所有其它局部变量的下面(比其它局部变量地址低)。

3)如果有多个局部变量,那么它们被分配的地址顺序是不能确定的。

4)参考其它文章(标注1)位置还有调用函数的EBX、ESI、EDI值,但是按照我的实验环境,并没有发现这些值。

5)_cdecl由调用函数清除压栈参数(调整ESP),而_stdcall由被调用者清除。在下面这个例子中。main调用了_cdecl fun,由main负责清除传递给fun的参数5000,100(b, a). fun调用了_stdcall foo,由foo清理3,2(n, m)

测试代码如下:

int  __stdcall foo(int m, int n)
{
	int p=0x12;
	int q=0x13;
	printf("the address of m is %p-->m=%X\n", &m,m);
	printf("the address of n is %p-->n=%X\n", &n,n);
	printf("the address of p is %p-->p=%X\n", &p,p);
	printf("the address of q is %p-->q=%X\n", &q,q);

	for (int i=0; i<20; i++)
	printf("the address of %p--->%X\n", (&q+i), *(&q+i));
	return p+q;
}

void  fun(int a, int b)
{
	
	int x=2;
	int z[2]={4,5};
	int y=3;
	printf("the address of a is %p-->a=%X\n", &a,a);
	printf("the address of b is %p-->b=%X\n", &b,b);
	printf("the address of x is %p-->x=%X\n", &x,x);
	printf("the address of y is %p-->y=%X\n", &y,y);
	printf("the address of z[0] is %p-->z[0]=%X\n", &z[0],z[0]);
	printf("the address of z[1] is %p-->z[1]=%X\n", &z[1],z[1]);
	foo(x, y);
}

int _tmain(int argc, _TCHAR* argv[])
{
	int c=0x987;
	int d=0x789;
	fun(0x100, 0x5000);
	return 0;
}
输出结果

the address of a is 0012FF60-->a=100
the address of b is 0012FF64-->b=5000
the address of x is 0012FF50-->x=2  //*** x声明在y之前,地址比y小(1)
the address of y is 0012FF54-->y=3
the address of z[0] is 0012FF48-->z[0]=4
the address of z[1] is 0012FF4C-->z[1]=5
the address of m is 0012FF40-->m=2
the address of n is 0012FF44-->n=3
the address of p is 0012FF34-->p=12 // ***p声明在q之前,地址比q大,结合(1)可说明小结3)
the address of q is 0012FF30-->q=13  
the address of 0012FF30--->13  // foo参数
the address of 0012FF34--->12 //  
the address of 0012FF38--->12FF58 // fun函数的EBP
the address of 0012FF3C--->40115D //返回地址
the address of 0012FF40--->2 //***
the address of 0012FF44--->3 //*** //fun函数调用_stdcall foo从右至左入栈(2)
the address of 0012FF48--->4 //*** fun函数局部数组地址总在栈顶,虽然它的声明在x和y之间。见小结2),紧接着的低地址为foo入栈参数,说明小结4)
the address of 0012FF4C--->5 //*** 
the address of 0012FF50--->2 // *** fun函数局部变量x地址
the address of 0012FF54--->3 // *** fun函数局部变量y地址
the address of 0012FF58--->12FF70 // main的EBP
the address of 0012FF5C--->401193 //fun返回地址
the address of 0012FF60--->100
the address of 0012FF64--->5000  //main调用_cdecl fun从右至左入栈,结合(2)可说明小结1)
the address of 0012FF68--->987
the address of 0012FF6C--->789
the address of 0012FF70--->12FFC0
the address of 0012FF74--->401425
the address of 0012FF78--->1
the address of 0012FF7C--->3835A8



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值