esp:扩展栈指针寄存器,是指针寄存器的一种,用于存放函数栈顶指针(栈顶指针)
ebp:扩展基址指针寄存器,也被称为帧指针寄存器,用于存放函数栈底指针(栈底指针)。
esp和ebp有什么关系呢?
ebp只是存取某时刻的esp,这个时刻就是进入一个函数内后,cpu会将esp的值赋给ebp,此时就可以通过ebp对栈进行操作,比如获取函数参数,局部变量等,实际上使用esp也可以,只是esp可能会变化,去数据的时候很不方便
下面我们通过一个例子来说明:
#include "stdio.h"int function_add(int a,int b);int main(){int a=1,b=1,sum=0;sum=function_add(a,b);printf("sum=%d",sum);return 0;}int function_add(int a,int b){return a+b;}
这段程序的功能是定义一个函数,实现两个参数相加,然后打印出来,下面来分析,
int a=1,b=1,sum=0;sum=function_add(a,b);
这两句反汇编如下:
7: int a=1,b=1,sum=0;00401038 C7 45 FC 01 00 00 00 mov dword ptr [ebp-4],1 ;偏移地址为[ebp-4]存放10040103F C7 45 F8 01 00 00 00 mov dword ptr [ebp-8],1;偏移地址为[ebp-8]存放100401046 C7 45 F4 00 00 00 00 mov dword ptr [ebp-0Ch],0;偏移地址为[ebp-0ch]存放08: sum=function_add(a,b);0040104D 8B 45 F8 mov eax,dword ptr [ebp-8];eax的值设置为100401050 50 push eax;压入栈00401051 8B 4D FC mov ecx,dword ptr [ebp-4];ecx的值设置为100401054 51 push ecx;入栈00401055 E8 AB FF FF FF call @ILT+0(function_add) (00401005)0040105A 83 C4 08 add esp,80040105D 89 45 F4 mov dword ptr [ebp-0Ch],eax
当执行到这段代码会调到function_add函数执行
call @ILT+0(function_add) (00401005)
这段一共push两次,假设在没有这两次push前,设esp=M,push两次后,esp=M-8
执行call语句 esp=M-12
function_add反汇编的代码为:
12: int function_add(int a,int b)13: {004010A0 55 push ebp004010A1 8B ECmov ebp,esp004010A3 83 EC 40 sub esp,40h004010A6 53 push ebx004010A7 56 push esi004010A8 57 push edi004010A9 8D 7D C0 lea edi,[ebp-40h]004010AC B9 10 00 00 00 mov ecx,10h004010B1 B8 CC CC CC CC mov eax,0CCCCCCCCh004010B6 F3 ABrep stos dword ptr [edi]14: return a+b;004010B8 8B 45 08 mov eax,dword ptr [ebp+8]004010BB 03 45 0C add eax,dword ptr [ebp+0Ch]15:16: }004010BE 5F pop edi004010BF 5E pop esi004010C0 5B pop ebx004010C1 8B E5mov esp,ebp004010C3 5D pop ebp004010C4 C3 ret
我们可以看到在函数前面,首先将ebp压入栈,然后将esp的值赋值给ebp,此时
esp=M-16,ebp的值和esp相同
push ebpmov ebp,esp
此时栈里情况为:
在函数里,都是通过ebp对栈的数据进行操作的,比如获取参数的值,
004010B8 8B 45 08 mov eax,dword ptr [ebp+8]004010BB 03 45 0C add eax,dword ptr [ebp+0Ch]
因为在函数里,esp的值可能是变化的,ebp的值不变,通过ebp来操作数据很方便
在最后:
004010C1 8B E5mov esp,ebp004010C3 5D pop ebp
将esp,ebp的值变成调用function_add之前的值,这样看起来只是实现函数的功能,其他并没有啥变化,再使用ret语句,返回去,然后继续往下执行语句
0040105A 83 C4 08 add esp,8
总结:
esp始终指向栈顶,ebp只要在调用函数时,取值为栈顶,这样可方便对数据的操作函数调用时,EBP的值入栈,然后ESP的值传给EBP。函数调用结束后,EBP将值传回ESP,ESP又指向了原来的栈顶地址。这样看起来只是实现函数的功能,其他看起来没有变化
如果觉得《对esp和ebp分析来了解函数的调用过程》对你有帮助,请点赞、收藏,并留下你的观点哦!