首先,插入一段代码:

#include <stdio.h>

 

int myadd(int x,int y)

{

 int z=x+y;

 return z;

}

int main()

{

 int a = 0xaaaaaaaa;

 int b = 0xbbbbbbbb;

 int c = myadd(a,b);

 printf("you should runhere!:%d\n");

 return 0;

}

VC6.0下运行该程序;

函数的调用过程——栈帧

转换成汇编语言:

函数的调用过程——栈帧

做一些概念的说明:

通用寄存器:EAX、EBX、ECX、EDX……

EIP(PC):程序计数器(保存正在执行指令的下一条指令地址)

ESP:栈顶

EBP:栈底

及一些汇编语言的含义:

mov   将数据放置区域

push:入栈

pop:出栈

add:两者相加

sub:相减

call:1.保存当前汇编指令的下一条指令地址(入栈保存),目的是为了恢复;

         2.跳转至目标函数的入口处(修改EIP)(jmp)

ret:1.将当前保存的函数的返回值的地址出栈;将弹出的数据修改EIP;

        2.常规的临时变量通过寄存器返回,从而将结果拿回。

 函数的调用过程——栈帧

对a、b进行入栈;

函数的调用过程——栈帧

函数的调用过程——栈帧

将b的值放在EAX中;

函数的调用过程——栈帧

将a的值放在ECX中;

函数的调用过程——栈帧

函数的调用过程——栈帧

形参实例化顺序:从右至左(先b后a);

函数的调用过程——栈帧

执行call命令:

函数的调用过程——栈帧

将下一条指令的地址00401093存入0018FEE4中(小端);

并跳转至myadd函数;

函数的调用过程——栈帧

修改EIP:

函数的调用过程——栈帧

跳转至myadd函数:

函数的调用过程——栈帧

开始执行myadd函数:

函数的调用过程——栈帧

函数的调用过程——栈帧

此时,EBP、ESP指向同一位置。

接下来执行 sub     ESP,44h;

函数的调用过程——栈帧

此时,蓝色框中形成栈帧结构,供myadd函数使用;EIP中存放的为myadd函数的地址。

函数的调用过程——栈帧

把a的值放在EAX里,再将a+b的值放在EAX里。

函数的调用过程——栈帧

然后:

函数的调用过程——栈帧

将EBP弹出,ESP上移;

函数的调用过程——栈帧

此时,栈帧结构释放,执行ret;

函数的调用过程——栈帧

EIP变为00401093,回到了下一条指令的地址。

再执行add   esp,8;

函数的调用过程——栈帧

过程调用结束,临时变量被释放。

返回值通过EAX寄存器返回。

函数调用结束。

相关文章: