示例:
int main()
{
int a = 10;
int b = 20;
int ret = 0;
ret = Add(a, b);
printf("ret=%d\n", ret);
system("pause");
return 0;
}
int Add(int x,int y)
{
int ret = 0;
ret = x + y;
return ret;
}
图片:
解析:
首先分配一块栈空间,用寄存器ebp,esp来保护,上面叫栈顶,下面叫栈底,esp(黑色)存放指向栈顶的指针,ebp(黑色)存放指向栈底的指针。
栈空间的使用是从高地址向低地址分配的,main函数结束来到--tmainCRTStartup(它调用main函数),而--tmainCRTStartup也被mainCRTStarup调用,也就是说main函数在调用前也被其他函数调用了,为每一次调用都开辟空间,如图给--tmainCRTStartup和mainCRTStarup都开辟了空间,空间的增长之后,esp(红色),ebp(红色)也向上走,维护--tmainCRTStartup这个栈帧,从高地址向低地址走,图倒过来画也可行,但最底下的空间依旧存在,一会儿还要回来。
-----------------------------------------------------------------------------------------------
进入main函数的反汇编:
push ebp,在栈顶开辟一块空间,栈顶esp增长(变绿色),把ebp放入,此ebp是--tmainCRTStartup的ebp,因为调用完main函数,要回到--tmainCRTStartup函数内部,找到自己的栈帧。
Mov ebp,esp,esp给ebp,就是ebp(绿色)也指向esp(绿色)在当前最上面,
sub esp,0E4h,给esp减去4Ch,相当于申请了一个大空间4Ch,esp上移(变橙色),这块空间就是暂时给main函数开辟的空间。
Push ebx;push esi;push edi;往上分配三个空间,esp向上挪(变蓝色),
lea edi,[ebp-4Ch],lea是加载有效地址,把[ebp-4Ch]放到edi里面,刚才esp减去4Ch和这里是在同一个位置,这里把这个地址给edi存放,
mov ecx,13h,13h是19,19乘以4是76,放到ecx里面,4Ch也是76,
mov eax,0CCCCCCCCh,0CCCCCCCCh是随机值,把随机值放到eax里面,
rep stos dword ptr [edi],从edi每次存储双字,四个字节,从edi开始向下重复赋值,重复赋值ecx次,赋的值是eax,栈顶esp就下降到(橙色),打开“内存” 输入栈顶esp就会出现其内存地址,往下四个就是edi,运行一下就会初始化19行CC CC CC CC,19乘以4就是76,初始化了76个字节,刚才三次push之后,栈底就跳到esi那里(有问题)
------------------------------------------------------------------------------------------------
开始执行代码,上面都是系统调用开销。
Mov dword ptr [ebp-4],0Ah向上挪四个字节,放入a=10。
Mov dword ptr [ebp-8],14h向上挪八个字节,放入b=20。
Mov dword ptr [ebp-0Ch],0向上挪十二个字节,放入ret=0。下来是函数调用,
mov eax,dword ptr [ebp-8];push eax;把实参拿出放过去,然后在栈顶放进去b的值,栈顶esp上移(变绿色)。
mov ecx,dword ptr [ebp-4];push ecx;在栈顶放入a的值栈顶esp上移(变暗红)。
call @ILT+30(_average) (00401023);记住call指令下一条指令的地址(00401023),记录其,当调用完回到Add函数。add esp,8;在“内存”中按F11,栈顶地址就变为(00401023),在栈顶悄悄地压入该地址,esp上移(变紫色)。
mov dword ptr [ebp-0Ch],eax;。
-----------------------------------------------------------------------------------------------
再走程序,进入Add函数,和刚才main函数前面一样。push ebp
在栈顶压入main函数的ebp,栈顶上移(变青蓝色)内存里的ebp也会随着改变(变红色),mov ebp,esp...,esp上移(变红色),为Add函数开辟空间,push三次ebx,esi,edi,esp上移(变黑色),内存又变,像上面所说一样也是初始化,17行。
-----------------------------------------------------------------------------------------------
Int ret=0;
Mov dword ptr [ebp-4],0给ebp减去4申请一个空间,四个字节存放ret=0,局部变量的创建。
-----------------------------------------------------------------------------------------------
ret=x+y;
mov eax,dword ptr [ebp+8];ebp+8向回指向到“把a给ecx,10”,把它再给eax。add eax,dword ptr [ebp+0Ch];ebp+0Ch]指向“把b给eax,20”,把它再给eax(此时是10)加,就相当于a+b,变成30。mov dword ptr [ebp-4],eax;加出来的结果放到ebp-4就是ret。
------------------------------------------------------------------------------------------------
return ret;
Mov eax,dword ptr [ebp-4];将ret的值给寄存器eax,是30。
pop edi; pop esi; pop ebx; 三次出栈,刚才放的都弹出,esp下移(变红色)
mov esp,ebp;esp再下移(变青蓝色),Add空间释放,ret局部变量也丢失,
pop ebp;把“ebp-main”弹出放到ebp中,这就是main函数的ebp回到main函数,
ret直接跳到刚才call指令记录的地方,call指令下是add esp,8,给esp加8,释放两个形参,到edi处(变蓝色),
mov dword otr [ebp-0Ch],eax 把eax(30)放到ebp-0Ch也就是ret中
-----------------------------------------------------------------------------------------------
printf(“ret=%d\n”,ret);
mov edx,dword ptr [ebp-0Ch] 通过寄存器带回参数
push edx
push offset string “...............
call printf (00401060)
add esp,8