#navi_header|C言語系| ''__stdcall'' 呼び出し規約: - 引数はスタック上にPUSHする。(主に右から左へPUSH) - ''関数(callee)側でスタックをクリーンアップする。'' -- アセンブラレベルでは ''RET imm16'' 命令を使って、戻る時にスタックポインタを"imm16"バイト分だけ戻す。つまり、"imm16"バイト分だけSPが増える(x86ではスタックはアドレスの小さい方へ進んでいくので、「戻る」=SPのアドレス値は大きくなる)。 #more|| ---- #outline|| ---- * サンプルコード ** callee.c (呼ばれる関数側) #code|c|> int foo1(int a) { return a * 2; } int foo2(int a, int b) { return a + b; } int foo3(int a, int b, int c) { return a + b + c; } int foo4(int a, int b, int c, int d) { return a + b + c + d; } ||< ** caller.c (呼ぶ main() 側) #code|c|> #include extern int foo1(int a); extern int foo2(int a, int b); extern int foo3(int a, int b, int c); extern int foo4(int a, int b, int c, int d); int __cdecl main(int argc, char *argv[]) { printf("foo1() = %d\n", foo1(10)); printf("foo2() = %d\n", foo2(10, 20)); printf("foo3() = %d\n", foo3(10, 20, 30)); printf("foo4() = %d\n", foo4(10, 20, 30, 40)); return 0; } ||< * VC++2008 Express Edtion : 指定方法 : #block||> int __stdcall foobar(); typedef int (__stdcall *ptr)(); ||< : コンパイラオプション : "/Gz" : 装飾名 : "_" + 関数名 + "@" + スタックのバイト数 コンパイル&リンク&実行 #pre||> > cl /FAs /TC /Od /nologo /c /Gz /Focallee_stdcall.obj callee.c > cl /FAs /TC /Od /nologo /c /Gz /Focaller_stdcall.obj caller.c > link /SUBSYSTEM:CONSOLE /NOLOGO /OUT:stdcall.exe caller_stdcall.obj callee_stdcall.obj > stdcall.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100 ||< ** callee.cのアセンブラ出力(callee.asm) #pre||> ; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01 TITLE C:\in_vitro\c\calling_conventions\callee.c .686P .XMM include listing.inc .model flat INCLUDELIB LIBCMT INCLUDELIB OLDNAMES PUBLIC _foo1@4 ; Function compile flags: /Odtp ; File c:\in_vitro\c\calling_conventions\callee.c _TEXT SEGMENT _a$ = 8 ; size = 4 _foo1@4 PROC ; 1 : int foo1(int a) { return a * 2; } push ebp mov ebp, esp mov eax, DWORD PTR _a$[ebp] shl eax, 1 pop ebp ret 4 _foo1@4 ENDP _TEXT ENDS PUBLIC _foo2@8 ; Function compile flags: /Odtp _TEXT SEGMENT _a$ = 8 ; size = 4 _b$ = 12 ; size = 4 _foo2@8 PROC ; 2 : int foo2(int a, int b) { return a + b; } push ebp mov ebp, esp mov eax, DWORD PTR _a$[ebp] add eax, DWORD PTR _b$[ebp] pop ebp ret 8 _foo2@8 ENDP _TEXT ENDS PUBLIC _foo3@12 ; Function compile flags: /Odtp _TEXT SEGMENT _a$ = 8 ; size = 4 _b$ = 12 ; size = 4 _c$ = 16 ; size = 4 _foo3@12 PROC ; 3 : int foo3(int a, int b, int c) { return a + b + c; } push ebp mov ebp, esp mov eax, DWORD PTR _a$[ebp] add eax, DWORD PTR _b$[ebp] add eax, DWORD PTR _c$[ebp] pop ebp ret 12 ; 0000000cH _foo3@12 ENDP _TEXT ENDS PUBLIC _foo4@16 ; Function compile flags: /Odtp _TEXT SEGMENT _a$ = 8 ; size = 4 _b$ = 12 ; size = 4 _c$ = 16 ; size = 4 _d$ = 20 ; size = 4 _foo4@16 PROC ; 4 : int foo4(int a, int b, int c, int d) { return a + b + c + d; } push ebp mov ebp, esp mov eax, DWORD PTR _a$[ebp] add eax, DWORD PTR _b$[ebp] add eax, DWORD PTR _c$[ebp] add eax, DWORD PTR _d$[ebp] pop ebp ret 16 ; 00000010H _foo4@16 ENDP _TEXT ENDS END ||< ** caller.cのアセンブラ出力(caller.asm) #pre||> ; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01 TITLE C:\in_vitro\c\calling_conventions\caller.c .686P .XMM include listing.inc .model flat INCLUDELIB LIBCMT INCLUDELIB OLDNAMES _DATA SEGMENT $SG2496 DB 'foo1() = %d', 0aH, 00H ORG $+3 $SG2497 DB 'foo2() = %d', 0aH, 00H ORG $+3 $SG2498 DB 'foo3() = %d', 0aH, 00H ORG $+3 $SG2499 DB 'foo4() = %d', 0aH, 00H _DATA ENDS PUBLIC _main EXTRN _foo4@16:PROC EXTRN _foo3@12:PROC EXTRN _foo2@8:PROC EXTRN _printf:PROC EXTRN _foo1@4:PROC ; Function compile flags: /Odtp ; File c:\in_vitro\c\calling_conventions\caller.c _TEXT SEGMENT _argc$ = 8 ; size = 4 _argv$ = 12 ; size = 4 _main PROC ; 9 : { push ebp mov ebp, esp ; 10 : printf("foo1() = %d\n", foo1(10)); push 10 ; 0000000aH call _foo1@4 push eax push OFFSET $SG2496 call _printf add esp, 8 ; 11 : printf("foo2() = %d\n", foo2(10, 20)); push 20 ; 00000014H push 10 ; 0000000aH call _foo2@8 push eax push OFFSET $SG2497 call _printf add esp, 8 ; 12 : printf("foo3() = %d\n", foo3(10, 20, 30)); push 30 ; 0000001eH push 20 ; 00000014H push 10 ; 0000000aH call _foo3@12 push eax push OFFSET $SG2498 call _printf add esp, 8 ; 13 : printf("foo4() = %d\n", foo4(10, 20, 30, 40)); push 40 ; 00000028H push 30 ; 0000001eH push 20 ; 00000014H push 10 ; 0000000aH call _foo4@16 push eax push OFFSET $SG2499 call _printf add esp, 8 ; 14 : return 0; xor eax, eax ; 15 : } pop ebp ret 0 _main ENDP _TEXT ENDS END ||< * Borland C++ Compiler * MinGW/MSYS * OpenWatcom Compiler(16bit) * OpenWatcom Compiler(32bit) * Turbo C++ 4.0J * GCC4.1.2 + binutils-2.7.50.0.6 (CentOS5.2) #navi_footer|C言語系|