简单的函数调用,通过反汇编可以清楚了解
举例:
#include <stdio.h>
int add(int a,int b)
{
int c=0;
c=a+b;
return c;
}
int main(void)
{
int x=0;
int y=3;
int z=4;
x=add(y,z);
return 0;
}
这是一个简单的通过调用函数计算两数之和的程序
VC6.0生成的汇编代码如下:
ebp:栈低(高地址),esp:栈顶(低地址)
add函数
push ebp //ebp=1000 esp=896
mov ebp,esp //ebp=896 esp=896 至此add栈往上依次是 main栈ebp,返回地址,参数
sub esp,44h //ebp=896 esp=828
push ebx
push esi
push edi //ebp=896 esp=816
lea edi,[ebp-44h]
mov ecx,11h
mov eax,0CCCCCCCCh
rep stos dword ptr [edi]
int c=0;
mov dword ptr [ebp-4],0
c=a+b;
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+0Ch]
mov dword ptr [ebp-4],eax
return c;
mov eax,dword ptr [ebp-4] //在add函数返回以前,都是在操作自己的局部变量的栈空间
pop edi
pop esi
pop ebx //ebp=896 esp=828 在add函数返回以前恢复寄存器的值
mov esp,ebp//ebp=896 esp=896
pop ebp //ebp=1000 esp=900
ret //ebp=1000 esp=904 把返回地址从main栈中弹出到指令寄存器 esp+4
main函数
push ebp
mov ebp,esp //得到main栈的栈顶地址,为了叙述方便假设此时的栈基址 ebp=1000 esp=1000
sub esp,4Ch //为main栈开辟76个字节的区域用于局部变量使用 ebp=1000 esp=924
push ebx
push esi
push edi //需要保护的寄存器值压栈 ebp=1000 esp=912
lea edi,[ebp-4Ch]
mov ecx,13h
mov eax,0CCCCCCCCh
rep stos dword ptr [edi] //局部变量初始化,debug模式下是此值,release模式局部变量为不定值
int x=0;
mov dword ptr [ebp-4],0
int y=3;
mov dword ptr [ebp-8],3
int z=4;
mov dword ptr [ebp-0Ch],4 //局部变量按照定义的顺序存储在main栈中
x=add(y,z);
mov eax,dword ptr [ebp-0Ch]
push eax
mov ecx,dword ptr [ebp-8]
push ecx //把参数按照stdcall方式从右到左压栈 ebp=1000 esp=904
call @ILT+15(_add) (00401014)//把返回地址压栈并跳转至add函数 ebp=1000 esp=900
add esp,8 //参数部分的出栈工作由调用函数来完成 ebp=1000 esp=912
mov dword ptr [ebp-4],eax //返回的变量放到x中
return 0;