函数的调用过程(栈帧)
2018-03-16 11:28
225 查看
我们知道每一次函数调用都是一个过程,这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存,现场保护,这块栈空间称之为栈帧。
首先我们来看一段简单的代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <math.h>
int add(int x,int y)
{
int z=0;
z=x+y;
return z;
}
int main()
{
int a=0xaaaaaaaa;
int b=0xbbbbbbbb;
int ret=add(a,b);
printf("ret=%d\n",a,b);
return 0;
}
我们发现其实main函数在_tmainCRTStartup函数中调用的,而 _tmainCRTStartup函数是在mainCRTStartup被调用的。
而栈帧的维护我们必须了解ebp,esp和eip三个寄存器,在函数调用的过程中这两个寄存器存放了维护这个栈的栈底和栈顶指针。
ebp存放了指向函数栈帧栈底的地址。
esp存放了指向函数栈帧栈顶的地址。
eip程序计数器:当前进行下条记录的地址。
当我们要详细研究函数调用过程,必须得对应汇编代码,从main函数的地方开始,要展开main函数的调用就得为main函数创建栈帧,那我们先来看main函数栈帧的创建
当执行到call指令的时候按F11,call指令有两个作用:1.将当前指令的下条指令地址,进行压栈保存。2.覆盖eip寄存器,达到函数跳转的命令。
接下来是add函数的调用。同时eip记录了调用add函数的下一条命令的地址并且入栈,以便于出栈时恢复现场。
剩下的就是函数返回部分,ret指令:覆盖eip。它会使得出栈一次,并将出栈的内容当做地址,让程序执行时跳转到该地址处。
首先我们来看一段简单的代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <math.h>
int add(int x,int y)
{
int z=0;
z=x+y;
return z;
}
int main()
{
int a=0xaaaaaaaa;
int b=0xbbbbbbbb;
int ret=add(a,b);
printf("ret=%d\n",a,b);
return 0;
}
我们发现其实main函数在_tmainCRTStartup函数中调用的,而 _tmainCRTStartup函数是在mainCRTStartup被调用的。
而栈帧的维护我们必须了解ebp,esp和eip三个寄存器,在函数调用的过程中这两个寄存器存放了维护这个栈的栈底和栈顶指针。
ebp存放了指向函数栈帧栈底的地址。
esp存放了指向函数栈帧栈顶的地址。
eip程序计数器:当前进行下条记录的地址。
当我们要详细研究函数调用过程,必须得对应汇编代码,从main函数的地方开始,要展开main函数的调用就得为main函数创建栈帧,那我们先来看main函数栈帧的创建
当执行到call指令的时候按F11,call指令有两个作用:1.将当前指令的下条指令地址,进行压栈保存。2.覆盖eip寄存器,达到函数跳转的命令。
接下来是add函数的调用。同时eip记录了调用add函数的下一条命令的地址并且入栈,以便于出栈时恢复现场。
剩下的就是函数返回部分,ret指令:覆盖eip。它会使得出栈一次,并将出栈的内容当做地址,让程序执行时跳转到该地址处。
相关文章推荐