函数的调用过程(栈帧)

来源:互联网 发布:线切割控制编程系统 编辑:程序博客网 时间:2024/05/21 14:50

我们研究一下函数的调用过程,首先看一段简单的代码:

#include<stdio.h>int add(int x,int y){    int z = 0;    z = x + y;    return z;}int main(){    int a = 10;    int b = 20;    int ret = add(a,b);    printf("ret = %d\n",ret);    return 0;}

EBP和ESP是寄存器,EBP指向栈底,ESP指向栈顶。程序的入口是main函数,进来以后,
执行 int a = 10;int b = 20。为变量a,b创建一个空间,先给a创建,再给b创建。a的地址比b的地址高。
这里写图片描述

临时变量在当前栈的栈顶位置,即esp的位置。函数参数赋值的顺序是右右往左,这是由栈帧决定的。
move eax,dword ptr [ebp-8]。[ebp-8]就是指b ,把b move到eax寄存器当中,eax是cpu里面的寄存器,然后把eax里的b push到栈中,此时ESP寄存器指向b的位置.
move ecx,dword ptr[ebp-4]。再把a压入栈中,ESP再移动指向a。这里[ebp-4]指a,(-4)指当前位置与首地址的偏移量因,所以a的地址比b的地址高。这里写图片描述

接下来
0040108E call @ILT+0(my_add) (00401093)
call的作用是把下一个地址压入当前的栈顶位置,即a的地址下面,比a的地址低。
然后是跳转jmp指令,跳转到my_add函数里面。这里写图片描述

move ebp,esp
esp指向哪,ebp就指向哪。
esp-44h
esp变小,往下移。
这个时候产生新的ebp和新的esp,产生my_add的栈帧。eip变成my_add的寄存器。
在my_add函数里面

int z = x + y;

move eax,dword ptr[ebp+8]
就是把a放到eax。
add eax,dword ptr[ebp+0Ch]
这里就把a和b加起来。
move dword ptr[ebp-4],eax
把加起来的结果放到eax里面。

return z;

就是下面的指令:

 move  eax,dword ptr[ebp-4]

把返回值放在eax里面。

接下来:

move esp,ebp

就是说,ebp指向哪里,esp就指向哪里。
这里写图片描述

pop  ebp

这里写图片描述
把栈顶的内容弹出来,即把main ebp移到ebp的位置,这样子就回到了最开始的位置。

把栈顶放到eip的位置,就回到了main函数。这个时候执行ret指令:

ret

这个指令走完过后,esp变成00401093。
这里写图片描述

在main函数里面

add esp+8

这里写图片描述
espz指向图示位置,过程调用完成。