堆栈之直观体验(二)

堆栈调用之初步探索

jefby.

Xidian University.

堆栈是一种数据结构,相信很多人都写过简单的栈操作(push,pop),但是对于其在函数调用方面的应用却很少有人真正了解,也就是说如何构建函数堆栈,如何进行函数调用及返回,函数执行时期堆栈结构到底是怎样的??相信学过汇编语言的人多少会有些了解,但是我相信只是大部分人的认识都只是停留在表面,那么请跟我一起来深入研究下程序执行时的堆栈情况,相信真正理解了这个原理之后,对你以后的代码编写,编程内功的提升都有着巨大的帮助作用。

下面从最通用的Intel体系结构入手,开始探索下堆栈细节。图一所示是程序栈情况。

                              

                                     图 1

当执行函数调用时,为了便于演示,定义函数void fun(int x,int y);

假设在main函数中调用此语句,例子程序如下:

0x3FFFFFFF  fun(1,2);//语句1

0x40000003  a = 1;//语句2

函数fun定义如下(为了展示函数调用的方法以及堆栈的结构)

void fun(intx,int y)//仅为了展示,代码无实际意义

{

   Int a,b;//语句3

   a = add(x,y);//语句4

   b = x – y;//语句5

}

函数add定义如下:

int add(intx,int y)//仅为了展示,代码无实际意义

{

   return x + y;//语句6

}

  

图 2

图2所示为函数执行到语句6时的堆栈结构,当第一次调用函数fun时,首先将参数从右向左入栈(在VC、VS2008中)默认的调用方式cdcel,然后执行call fun,此时,首先将返回地址0x40000003压入堆栈,并将fun函数的地址赋给EIP,转而执行fun函数,首先函数fun被译为一般源码为:

        push EBP

        mov  EBP,ESP

即首先保存旧的EBP值,然后将EBP指向当前ESP所指向的位置,如图2所示,然后ESP-8,给局部变量a,b分配存储空间,然后又开始调用函数add,此时,首先从右向左将参数压入堆栈,然后开始执行call add,将add的地址赋值给EIP,同时将返回地址压入堆栈,从而执行add,同fun函数类似,保存旧的EBP,同时将EBP指向当前ESP所指向的位置,开始执行语句6,此句将a+b的和赋值给EAP,并通过EAP返回,此时将EAP的值赋值给变量a;当执行ret时,首先,执行语句

          Push ESP,EBP ;回收分配的栈空间

          Pop EBP      ; 恢复保存在堆栈中的旧EBP值

同时将返回地址即[ESP]赋值给EIP,继而执行语句5,此时的堆栈如图3所示:

                    

图 3

语句5执行完成之后,fun函数也执行完了,那么进入ret语句,此时与add函数ret语句类似,执行语句

          Push ESP,EBP ;回收分配的栈空间

          Pop EBP      ; 恢复保存在堆栈中的旧EBP值

同时将返回地址0x40000003赋值给EIP,此时堆栈如图4所示,

                          

图 4

即堆栈已经被清空,按照不同的调用标准(_stdcall,_cdcel等),如果是_stdcall的话是被调用者清理堆栈,如果是_cdcel的话是调用者清理堆栈,这里的清理堆栈主要负责清理的是函数调用时传递的参数(实参)。先写到这里吧,太晚了,后面会继续整理一些更加高级的用法,敬请期待。有什么问题可以email我,邮件地址jef199006@gmail.com。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值