由C代码到汇编代码来看看cdecl、stdcall、fastcall三个调用约定的区别:
int __stdcall add1(int x,int y) { return x + y; } int __cdecl add2(int x, int y) { return x + y; } int __fastcall add3(int x, int y,int z) { return x + y +z; } int _tmain(int argc, _TCHAR* argv[]) { add1(1,2); add2(1, 2); add3(1, 2, 3); return 0; }
main函数里面的反汇编代码:
int _tmain(int argc, _TCHAR* argv[]) { 001B14A0 push ebp 001B14A1 mov ebp,esp 001B14A3 sub esp,0C0h 001B14A9 push ebx 001B14AA push esi 001B14AB push edi 001B14AC lea edi,[ebp-0C0h] 001B14B2 mov ecx,30h 001B14B7 mov eax,0CCCCCCCCh 001B14BC rep stos dword ptr es:[edi] add1(1,2); 001B14BE push 2 001B14C0 push 1 001B14C2 call add1 (01B1032h) add2(1, 2); 001B14C7 push 2 001B14C9 push 1 001B14CB call add2 (01B102Dh) 001B14D0 add esp,8 add3(1, 2, 3); 001B14D3 push 3 001B14D5 mov edx,2 001B14DA mov ecx,1 001B14DF call add3 (01B100Ah) return 0; 001B14E4 xor eax,eax } 001B14E6 pop edi 001B14E7 pop esi 001B14E8 pop ebx 001B14E9 add esp,0C0h 001B14EF cmp ebp,esp 001B14F1 call __RTC_CheckEsp (01B114Fh) 001B14F6 mov esp,ebp 001B14F8 pop ebp 001B14F9 ret
对照源码,从表面上看,stdcall和fastcall传递参数方式为从右至左,由自身清理堆栈。
int __stdcall add1(int x,int y) { 001B13D0 push ebp 001B13D1 mov ebp,esp 001B13D3 sub esp,0C0h 001B13D9 push ebx 001B13DA push esi 001B13DB push edi 001B13DC lea edi,[ebp-0C0h] 001B13E2 mov ecx,30h 001B13E7 mov eax,0CCCCCCCCh 001B13EC rep stos dword ptr es:[edi] return x + y; 001B13EE mov eax,dword ptr [x] 001B13F1 add eax,dword ptr [y] } 001B13F4 pop edi 001B13F5 pop esi 001B13F6 pop ebx 001B13F7 mov esp,ebp 001B13F9 pop ebp 001B13FA ret 8 //自身清理堆栈
而cdecl为从右至左传递参数,由调用者清理堆栈。
001B14C7 push 2 001B14C9 push 1 001B14CB call add2 (01B102Dh) 001B14D0 add esp,8
fastcall传递参数很快,适合大程序的优化,前两个由EDX和ECX来传递,多出来的用push方式传递参数:
001B14D3 push 3 001B14D5 mov edx,2 001B14DA mov ecx,1 001B14DF call add3 (01B100Ah)
int __fastcall add3(int x, int y,int z) { 001B1450 push ebp 001B1451 mov ebp,esp 001B1453 sub esp,0D8h 001B1459 push ebx 001B145A push esi 001B145B push edi 001B145C push ecx 001B145D lea edi,[ebp-0D8h] 001B1463 mov ecx,36h 001B1468 mov eax,0CCCCCCCCh 001B146D rep stos dword ptr es:[edi] 001B146F pop ecx //由于先借由ecx来初始化,所以先push保存,后pop恢复 001B1470 mov dword ptr [y],edx 001B1473 mov dword ptr [x],ecx return x + y + z; 001B1476 mov eax,dword ptr [x] 001B1479 add eax,dword ptr [y] 001B147C add eax,dword ptr [z] } 001B147F pop edi 001B1480 pop esi 001B1481 pop ebx 001B1482 mov esp,ebp 001B1484 pop ebp 001B1485 ret 4 //由自身清理堆栈
时间: 2024-10-12 13:11:04