C++函数调用原理理解

来源:互联网 发布:表白扣字软件 编辑:程序博客网 时间:2024/06/06 02:29

空程序:

int main()

{

00411360 push ebp ;压入ebp

00411361 mov ebp,esp ;ebp = esp,保留esp,待函数调用完再恢复,因为函数调用中肯定会用到esp.

00411363 sub esp,0C0h ;esp-=0C0h(192);为该函数留出临时存储区

;将其他指针或寄存器中的值入栈,以便在函数中使用这些寄存器。

00411369 push ebx ;压入ebx

0041136A push esi ;压入esi

0041136B push edi ;压入edi

0041136C lea edi,[ebp-0C0h] ;读入[ebp-0C0h]有效地址,即原esp-0C0h,正好是为该函数留出的临时存储区的最低位

00411372 mov ecx,30h ;ecx = 30h(48),30h*4 = 0C0h

00411377 mov eax,0CCCCCCCCh ;eax = 0CCCCCCCCh;

0041137C rep stos dword ptr es:[edi] ;重复在es:[edi]存入30个;0CCCCCCCCh? Debug模式下把Stack上的变量初始化为0xcc,检查未初始化的问题

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,0F0h ;一共留了0F0h(240)空间

004113D9 push ebx

004113DA push esi

004113DB push edi

004113DC lea edi,[ebp-0F0h]

004113E2 mov ecx,3Ch ; ecx = 3C(60),3C*4 = 0F0h,

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

004113F5 mov dword ptr [b],2

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]

0041140A push ecx

0041140B mov edx,dword ptr [a]

0041140E push edx

调用Fun1

0041140F call Fun1 (4111DBh) ;Call调用时将下一行命令的EIP压入堆栈

恢复因为Fun1参数入栈改变的栈指针,因为Fun1有3个参数,一个整数4个字节,共0Ch(12)个字节

00411414 add esp,0Ch

00411417 mov dword ptr [d],eax

将返回值保存在d中.

return 0;

返回值为0,让eax清零

0041141A xor eax,eax

 

}

 

恢复现场

0041141C pop edi

0041141D pop esi

0041141E pop ebx

以下全为运行时ESP检查:

先恢复因为为main预留空间而改变的栈指针

0041141F add esp,0F0h

00411425 cmp ebp,esp

00411427 call @ILT+320(__RTC_CheckEsp) (411145h)

正常时只需要以下两句就可以正常恢复esp,再出栈,又可以恢复ebp.

0041142C mov esp,ebp

0041142E pop ebp

0041142F ret ;main返回


int Fun1(int a, int b, int c)

{

同上理解, 保存现场

00411A70 push ebp

00411A71 mov ebp,esp

00411A73 sub esp,0E4h ;留了0E4H(228)空间,

00411A79 push ebx

00411A7A push esi

00411A7B push edi

00411A7C lea edi,[ebp-0E4h]

00411A82 mov ecx,39h ; 39H(57)*4 = 0E4H(228)

00411A87 mov eax,0CCCCCCCCh

00411A8C rep stos dword ptr es:[edi]

int d = 4, e = 5;

定义变量

00411A8E mov dword ptr [d],4

00411A95 mov dword ptr [e],5

 

int f = Fun2(a, b, c, d, e);

再次参数反向入栈

00411A9C mov eax,dword ptr [e]

00411A9F push eax

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

 

调用Fun2

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

00411AC0 pop ebx

 

以下全为运行时ESP检查:

先恢复因为预留函数存储控件而改变的栈指针,

00411AC1 add esp,0E4h

再比较ebp,esp,假如程序运行正确,两个值应该相等.

00411AC7 cmp ebp,esp

00411AC9 call @ILT+320(__RTC_CheckEsp) (411145h)

正常时只需要以下两句就可以正常恢复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

0041205A push esi

0041205B push edi

0041205C lea edi,[ebp-0E4h]

00412062 mov ecx,39h ; 39H(57)*4 = 0E4H(228)

00412067 mov eax,0CCCCCCCCh

0041206C rep stos dword ptr es:[edi]

 

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

0041207C mov eax,dword ptr [a]

0041207F add eax,dword ptr [b]

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

0041209A mov esp,ebp

0041209C pop ebp

0041209D ret ;返回fun1 ,从pop堆栈中的EIP开始执行

原创粉丝点击