C++函数调用原理理解
空程序:
int main()
{
00411360 push ebp ;压入ebp
00411361 mov ebp,esp ;ebp = esp,保留esp,待函数调用完再恢复,因为函数调用中肯定会用到esp.
00411363 sub esp,
;将其他指针或寄存器中的值入栈,以便在函数中使用这些寄存器。
00411369 push ebx ;压入ebx
0041136B push edi ;压入edi
00411372 mov ecx,30h ;ecx = 30h(48),30h*4 =
00411377 mov eax,0CCCCCCCCh ;eax = 0CCCCCCCCh;
return 0;
0041137E xor eax,eax ;将eax清零,作为返回值
}
;各指针出栈
00411380 pop edi ;弹出edi
00411381 pop esi ;弹出esi
00411382 pop ebx ;弹出ebx
00411383 mov esp,ebp ;esp复原
00411385 pop ebp ;弹出ebp,也复原
00411386 ret ;返回
函数调用:
int _tmain(int argc, _TCHAR* argv[])
{
同上理解, 保存现场
004113D0 push ebp
004113D1 mov ebp,esp
004113D3 sub esp,
004113D9 push ebx
004113DA push esi
004113DB push edi
004113DC lea edi,[ebp
004113E2 mov ecx,3Ch ; ecx =
004113E7 mov eax,0CCCCCCCCh
004113EC rep stos dword ptr es:[edi]
同上理解.
int a = 1, b = 2, c = 3;
定义a,b,c并存储在为函数留出的临时存储空间中.
004113EE mov dword ptr [a],1
004113FC mov dword ptr [c],3
int d = Fun1(a, b, c);
参数反向入栈
00411403 mov eax,dword ptr [c]
00411406 push eax
00411407 mov ecx,dword ptr [b]
0041140B mov edx,dword ptr [a]
0041140E push edx
恢复因为Fun1参数入栈改变的栈指针,因为Fun1有3个参数,一个整数4个字节,共0Ch(12)个字节
00411414 add esp,0Ch
00411417 mov dword ptr [d],eax
将返回值保存在d中.
return 0;
返回值为0,让eax清零
}
恢复现场
0041141D pop esi
0041141E pop ebx
以下全为运行时ESP检查:
先恢复因为为main预留空间而改变的栈指针
00411425 cmp ebp,esp
00411427 call @ILT+320(__RTC_CheckEsp) (411145h)
正常时只需要以下两句就可以正常恢复esp,再出栈,又可以恢复ebp.
0041142E pop ebp
int Fun1(int a, int b, int c)
{
同上理解, 保存现场
int d = 4, e = 5;
定义变量
int f = Fun2(a, b, c, d, e);
再次参数反向入栈
00411AA0 mov ecx,dword ptr [d]
00411AA3 push ecx
00411AA4 mov edx,dword ptr [c]
00411AA7 push edx
00411AA8 mov eax,dword ptr [b]
00411AAB push eax
00411AAC mov ecx,dword ptr [a]
00411AAF push ecx
00411AB0 call Fun2 (4111D6h) ;Call调用时将下一行命令的EIP压入堆栈
00411AB5 add esp,14h ;恢复因为参数入栈改变的栈指针,因为Fun2有5个参数,一个整数4个字节,共14h(20)个字节
将Fun2函数的返回值(保存在eax中),赋值给f;
00411AB8 mov dword ptr [f],eax
return f;
将保留在f中的Fun1的返回值保存在eax中返回
00411ABB mov eax,dword ptr [f]
}
恢复现场
00411ABE pop edi
00411ABF pop esi
以下全为运行时ESP检查:
先恢复因为预留函数存储控件而改变的栈指针,
再比较ebp,esp,假如程序运行正确,两个值应该相等.
正常时只需要以下两句就可以正常恢复esp,再出栈,又可以恢复ebp.
00411ACE mov esp,ebp
00411AD0 pop ebp
返回main从pop堆栈中的EIP开始执行
00411AD1 ret
int Fun2(int a, int b, int c, int d, int e)
{
同上理解, 保存现场
00412050 push ebp
00412051 mov ebp,esp
00412053 sub esp,0E4h ;保留0E4H(228)
00412059 push ebx
0041205B push edi
00412062 mov ecx,39h ; 39H(57)*4 = 0E4H(228)
00412067 mov eax,0CCCCCCCCh
int f = 6, g = 7;
定义变量
0041206E mov dword ptr [f],6
00412075 mov dword ptr [g],7
int h = a + b + c + d + e + f + g;
相加,存入a,再保存在h
00412082 add eax,dword ptr [c]
00412085 add eax,dword ptr [d]
00412088 add eax,dword ptr [e]
0041208B add eax,dword ptr [f]
0041208E add eax,dword ptr [g]
00412091 mov dword ptr [h],eax
return h;
将返回值h的值保存在eax中
00412094 mov eax,dword ptr [h]
}
恢复现场
00412097 pop edi
00412098 pop esi
00412099 pop ebx
0041209D ret ;返回fun1 ,从pop堆栈中的EIP开始执行
Posted By 九天雁翎 at 九天雁翎的博客 on 2008年06月01日