呼び出し規約について
引数の渡し規則と名前付け規則 に説明がある。
引数の渡し方、呼び出し側 (caller)、呼び出され側 (callee) のどちらが Stack Cleanup を行うか書いてある。以下のコードで確認してみる。
int func (int arg1, int arg2) { return arg1 + arg2; } int __stdcall func_stdcall (int arg1, int arg2) { return arg1 + arg2; } int __cdecl func_cdecl (int arg1, int arg2) { return arg1 + arg2; } int __fastcall func_fastcall (int arg1, int arg2) { return arg1 + arg2; } int main (int argc, char * argv []) { int arg1 = 1; int arg2 = 2; int rslt = 0; rslt = func (arg1, arg2); rslt = func_stdcall (arg1, arg2); rslt = func_cdecl (arg1, arg2); rslt = func_fastcall (arg1, arg2); return 0; }
結果
0:000> uf main!main main!main: 22 00321090 55 push ebp 22 00321091 8bec mov ebp,esp 22 00321093 83ec0c sub esp,0Ch 23 00321096 c745f401000000 mov dword ptr [ebp-0Ch],1 24 0032109d c745fc02000000 mov dword ptr [ebp-4],2 25 003210a4 c745f800000000 mov dword ptr [ebp-8],0 27 003210ab 8b45fc mov eax,dword ptr [ebp-4] 27 003210ae 50 push eax 27 003210af 8b4df4 mov ecx,dword ptr [ebp-0Ch] 27 003210b2 51 push ecx 27 003210b3 e84dffffff call main!ILT+0(?funcYAHHHZ) (00321005) 27 003210b8 83c408 add esp,8 27 003210bb 8945f8 mov dword ptr [ebp-8],eax 28 003210be 8b55fc mov edx,dword ptr [ebp-4] 28 003210c1 52 push edx 28 003210c2 8b45f4 mov eax,dword ptr [ebp-0Ch] 28 003210c5 50 push eax 28 003210c6 e83fffffff call main!ILT+5(?func_stdcallYGHHHZ) (0032100a) 28 003210cb 8945f8 mov dword ptr [ebp-8],eax 29 003210ce 8b4dfc mov ecx,dword ptr [ebp-4] 29 003210d1 51 push ecx 29 003210d2 8b55f4 mov edx,dword ptr [ebp-0Ch] 29 003210d5 52 push edx 29 003210d6 e839ffffff call main!ILT+15(?func_cdeclYAHHHZ) (00321014) 29 003210db 83c408 add esp,8 29 003210de 8945f8 mov dword ptr [ebp-8],eax 30 003210e1 8b55fc mov edx,dword ptr [ebp-4] 30 003210e4 8b4df4 mov ecx,dword ptr [ebp-0Ch] 30 003210e7 e82dffffff call main!ILT+20(?func_fastcallYIHHHZ) (00321019) 30 003210ec 8945f8 mov dword ptr [ebp-8],eax 32 003210ef 33c0 xor eax,eax 33 003210f1 8be5 mov esp,ebp 33 003210f3 5d pop ebp 33 003210f4 c3 ret
0:000> uf main!func main!func: 2 00321040 55 push ebp 2 00321041 8bec mov ebp,esp 3 00321043 8b4508 mov eax,dword ptr [ebp+8] 3 00321046 03450c add eax,dword ptr [ebp+0Ch] 4 00321049 5d pop ebp 4 0032104a c3 ret
0:000> uf main!func_stdcall main!func_stdcall: 7 00321050 55 push ebp 7 00321051 8bec mov ebp,esp 8 00321053 8b4508 mov eax,dword ptr [ebp+8] 8 00321056 03450c add eax,dword ptr [ebp+0Ch] 9 00321059 5d pop ebp 9 0032105a c20800 ret 8
0:000> uf main!func_cdecl main!func_cdecl: 12 00321060 55 push ebp 12 00321061 8bec mov ebp,esp 13 00321063 8b4508 mov eax,dword ptr [ebp+8] 13 00321066 03450c add eax,dword ptr [ebp+0Ch] 14 00321069 5d pop ebp 14 0032106a c3 ret
0:000> uf main!func_fastcall main!func_fastcall: 17 00321070 55 push ebp 17 00321071 8bec mov ebp,esp 17 00321073 83ec08 sub esp,8 17 00321076 8955f8 mov dword ptr [ebp-8],edx 17 00321079 894dfc mov dword ptr [ebp-4],ecx 18 0032107c 8b45fc mov eax,dword ptr [ebp-4] 18 0032107f 0345f8 add eax,dword ptr [ebp-8] 19 00321082 8be5 mov esp,ebp 19 00321084 5d pop ebp 19 00321085 c3 ret
func と func_decl では、caller が add esp,8 で 8 バイト分スタック ポインタを戻しているのがわかる。
一方、func_stdcall では callee が ret 8 で 8 バイト分スタック ポインタを戻している。
また、func_fastcall では、今回のケースでは引数の受け渡しにスタックは使用されず、edx と ecx レジスタが使われているようだ。