C语言函数调过程栈帧,C函数的调用过程   栈帧

C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。

首先,栈是从高地址向低地址延伸的。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)。

先来看一个代码

#include 

void fun()

{

int tmp = 10;

int*p = (int*)(*(&tmp + 1));

*(p - 1) = 20;

}

int main()

{

int a = 0;

fun();

printf("a = %d\n", a);

return 0;

}

这个代码输出的a的值时多少呢?  答案是20。

81a7e0b502daa1610b220d27dc961bbb.gif

调用fun()函数后居然把a的值改掉了,从上面的代码可以看到并没有给fun()函数传a的地址,那么fun()函数为什么会把a的值改掉呢?  回答这个问题之前我们需要了解C语言函数的调用过程。

为了更好的观察到上述函数的调用过程,我们在VC 6.0环境下查看一下它的汇编代码。

在这之前首先要知道:

寄存器ebp称为“基址指针”,在未受改变之前始终指向栈底,用途是:在堆栈中寻址。

寄存器esp称为“栈指针”,会随着数据的入栈出栈移动,也就是说始终指向栈 顶。

6ace82c184c2f2153435b13ce0d95b5d.png

函数调用过程如下图所示:

图中有部分esp移动的过程没有画出,但最终不管如何入栈出栈esp会在销毁空间后指向创建空间前esp最后指向的位置

f69824092ac6723912385b6068441946.png          从上面的汇编代码,我们可以看到fun()函数是通过找到变量a所在的栈的栈底地址,进而找到a的地

址,将a的内容改掉,这就解释了为什么没有给fun()传a的地址,却可以改变a的值。

总结:

函数在调用另一个函数之前会保存两个信息(1)函数调用完返回之后下一条指令的地址

(2)该函数的栈底的地址

ad571a220dbc9b7f5e485a189ff4ccf2.png

最后分享一个使用ebp修改程序执行顺序的代码,并且最后esp回到原处,貌似什么都没发生的样子。

但是却在屏幕上多输出了一个funtest

#include 

void*p =NULL;

void*q =NULL;

void funtest()

{

int tmp =0;

int tmp2 =1;

printf("funtest\n");

*(int*)(&tmp+2) =p;

}

void swap(int *pa, int *pb)

{

int tmp=0;

p= *(&tmp+2);

q= &tmp+2;

*(&tmp+2) = &funtest;

tmp = *pa;

*pa = *pb;

*pb = tmp;

}

int main()

{

int a =10;

int b =20;

swap(&a,&b);

printf("main\n");

_asm{

sub esp,4

}

return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值