#navi_header|C言語系| ''__pascal'' 呼び出し規約: - 引数はスタック上に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 (obsoleted) 2010年現在、VC++2008では "__pascal" 呼び出し規約はサポートされていない。(obsoleted) - Obsolete Calling Conventions (C++) -- http://msdn.microsoft.com/ja-jp/library/wda6h6df%28VS.80%29.aspx 実際に次のようなコード(pascal.c)をコンパイルしようとすると、関数宣言のところでエラーになり、コンパイルに失敗する。 #code|c|> #include int __pascal foo(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); return 0; } ||< コンパイル→エラー、失敗: #pre||> > cl /TC /Od /nologo /c pascal.c pascal.c pascal.c(3) : error C2061: 構文エラー : 識別子 'foo' pascal.c(3) : error C2059: 構文エラー : ';' pascal.c(3) : error C2059: 構文エラー : '型' ||< * Borland C++ Compiler : 指定方法 : #block||> int __pascal foobar(); typedef int (__pascal *ptr)(); ||< : コンパイラオプション : "-p" : 装飾名 : 関数名の英字が全て大文字に変換される。 アセンブラコードを生成 > bcc32 -Od -p -S callee.c > bcc32 -Od -p -S caller.c コンパイル&リンク&実行 #pre||> > bcc32 -Od -p -c -ocallee_pascal.obj callee.c > bcc32 -Od -p -c -ocaller_pascal.obj caller.c > ilink32 /c /ap /Tpe c0x32 caller_pascal callee_pascal, pascal, , cw32 import32 > pascal.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100 ||< ** callee.c のアセンブラ出力(callee.asm) #pre||> .386p ifdef ??version if ??version GT 500H .mmx endif endif model flat ifndef ??version ?debug macro endm endif ?debug S "callee.c" ?debug T "callee.c" _TEXT segment dword public use32 'CODE' _TEXT ends _DATA segment dword public use32 'DATA' _DATA ends _BSS segment dword public use32 'BSS' _BSS ends DGROUP group _BSS,_DATA _TEXT segment dword public use32 'CODE' FOO1 proc near ?live1@0: ; ; int foo1(int a) { return a * 2; } ; push ebp mov ebp,esp @1: mov eax,dword ptr [ebp+8] add eax,eax @3: @2: pop ebp ret 4 FOO1 endp FOO2 proc near ?live1@32: ; ; int foo2(int a, int b) { return a + b; } ; push ebp mov ebp,esp @4: mov eax,dword ptr [ebp+12] add eax,dword ptr [ebp+8] @6: @5: pop ebp ret 8 FOO2 endp FOO3 proc near ?live1@64: ; ; int foo3(int a, int b, int c) { return a + b + c; } ; push ebp mov ebp,esp @7: mov eax,dword ptr [ebp+16] add eax,dword ptr [ebp+12] add eax,dword ptr [ebp+8] @9: @8: pop ebp ret 12 FOO3 endp FOO4 proc near ?live1@96: ; ; int foo4(int a, int b, int c, int d) { return a + b + c + d; } ; push ebp mov ebp,esp @10: mov eax,dword ptr [ebp+20] add eax,dword ptr [ebp+16] add eax,dword ptr [ebp+12] add eax,dword ptr [ebp+8] @12: @11: pop ebp ret 16 FOO4 endp _TEXT ends public FOO1 public FOO2 public FOO3 public FOO4 ?debug D "callee.c" 15473 24064 end ||< ** caller.cのアセンブラ出力(caller.asm) #pre||> .386p ifdef ??version if ??version GT 500H .mmx endif endif model flat ifndef ??version ?debug macro endm endif ?debug S "caller.c" ?debug T "caller.c" _TEXT segment dword public use32 'CODE' _TEXT ends _DATA segment dword public use32 'DATA' _DATA ends _BSS segment dword public use32 'BSS' _BSS ends DGROUP group _BSS,_DATA _TEXT segment dword public use32 'CODE' _main proc near ?live1@0: ; ; int __cdecl main(int argc, char *argv[]) ; push ebp mov ebp,esp ; ; { ; printf("foo1() = %d\n", foo1(10)); ; @1: push 10 call FOO1 push eax push offset s@ call _printf add esp,8 ; ; printf("foo2() = %d\n", foo2(10, 20)); ; push 10 push 20 call FOO2 push eax push offset s@+13 call _printf add esp,8 ; ; printf("foo3() = %d\n", foo3(10, 20, 30)); ; push 10 push 20 push 30 call FOO3 push eax push offset s@+26 call _printf add esp,8 ; ; printf("foo4() = %d\n", foo4(10, 20, 30, 40)); ; push 10 push 20 push 30 push 40 call FOO4 push eax push offset s@+39 call _printf add esp,8 ; ; return 0; ; xor eax,eax ; ; } ; @3: @2: pop ebp ret _main endp _TEXT ends _DATA segment dword public use32 'DATA' s@ label byte ; s@+0: db "foo1() = %d",10,0 ; s@+13: db "foo2() = %d",10,0 ; s@+26: db "foo3() = %d",10,0 ; s@+39: db "foo4() = %d",10,0 align 4 _DATA ends _TEXT segment dword public use32 'CODE' _TEXT ends public _main extrn __setargv__:near extrn _printf:near extrn FOO1:near extrn FOO2:near extrn FOO3:near extrn FOO4:near ?debug D "C:\in_vitro\apps\borland\bcc55\include\_nfile.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_null.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_defs.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_stddef.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\stdio.h" 10339 10240 ?debug D "caller.c" 15473 24232 end ||< * OpenWatcom Compiler(16bit) * OpenWatcom Compiler(32bit) * Turbo C++ 4.0J(TC4J) TC4Jで、コマンドラインからの呼び出し規約指定オプションが不明だった為、gcc系列と同様、CALLINGCONVを"-D"でdefineすることにより切り替える方式を採った。 なお、TC4Jについてはリンク&実行までは行っていない。 : 指定方法 : #block||> int __pascal foobar(); typedef int (__pascal *ptr)(); ||< : 装飾名 : 関数名の英字が全て大文字に変換される。 アセンブラコードを生成 > tcc -DCALLINGCONV=__pascal -S callee.c > tcc -DCALLINGCONV=__pascal -S caller.c ** callee.c のアセンブラ出力(callee.asm) #pre||> .286p ifndef ??version ?debug macro endm publicdll macro name public name endm $comm macro name,dist,size,count comm dist name:BYTE:count*size endm else $comm macro name,dist,size,count comm dist name[size]:BYTE:count endm endif ?debug V 301h ?debug S "callee.c" ?debug C E91593723C0863616C6C65652E63 _TEXT segment byte public 'CODE' _TEXT ends DGROUP group _DATA,_BSS assume cs:_TEXT,ds:DGROUP _DATA segment word public 'DATA' d@ label byte d@w label word _DATA ends _BSS segment word public 'BSS' b@ label byte b@w label word _BSS ends _TEXT segment byte public 'CODE' ; ; int CALLINGCONV foo1(int a) { return a * 2; } ; assume cs:_TEXT,ds:DGROUP FOO1 proc near push bp mov bp,sp mov ax,word ptr [bp+4] add ax,ax pop bp ret 2 pop bp ret 2 FOO1 endp ; ; int CALLINGCONV foo2(int a, int b) { return a + b; } ; assume cs:_TEXT,ds:DGROUP FOO2 proc near push bp mov bp,sp mov ax,word ptr [bp+6] add ax,word ptr [bp+4] pop bp ret 4 pop bp ret 4 FOO2 endp ; ; int CALLINGCONV foo3(int a, int b, int c) { return a + b + c; } ; assume cs:_TEXT,ds:DGROUP FOO3 proc near push bp mov bp,sp mov ax,word ptr [bp+8] add ax,word ptr [bp+6] add ax,word ptr [bp+4] pop bp ret 6 pop bp ret 6 FOO3 endp ; ; int CALLINGCONV foo4(int a, int b, int c, int d) { return a + b + c + d; } ; assume cs:_TEXT,ds:DGROUP FOO4 proc near push bp mov bp,sp mov ax,word ptr [bp+10] add ax,word ptr [bp+8] add ax,word ptr [bp+6] add ax,word ptr [bp+4] pop bp ret 8 pop bp ret 8 FOO4 endp ?debug C E9 ?debug C FA00000000 _TEXT ends _DATA segment word public 'DATA' s@ label byte _DATA ends _TEXT segment byte public 'CODE' _TEXT ends _s@ equ s@ public FOO1 public FOO2 public FOO3 public FOO4 end ||< ** caller.c のアセンブラ出力(caller.asm) #pre||> .286p ifndef ??version ?debug macro endm publicdll macro name public name endm $comm macro name,dist,size,count comm dist name:BYTE:count*size endm else $comm macro name,dist,size,count comm dist name[size]:BYTE:count endm endif ?debug V 301h ?debug S "caller.c" ?debug C E9D2A0723C0863616C6C65722E63 ?debug C E900207F1E16433A5C5443345C494E434C5544455C737464696F2E+ ?debug C 68 ?debug C E900207F1E16433A5C5443345C494E434C5544455C5F646566732E+ ?debug C 68 ?debug C E900207F1E17433A5C5443345C494E434C5544455C5F6E66696C65+ ?debug C 2E68 ?debug C E900207F1E16433A5C5443345C494E434C5544455C5F6E756C6C2E+ ?debug C 68 _TEXT segment byte public 'CODE' _TEXT ends DGROUP group _DATA,_BSS assume cs:_TEXT,ds:DGROUP _DATA segment word public 'DATA' d@ label byte d@w label word _DATA ends _BSS segment word public 'BSS' b@ label byte b@w label word _BSS ends _TEXT segment byte public 'CODE' ; ; int __cdecl main(int argc, char *argv[]) ; assume cs:_TEXT,ds:DGROUP _main proc near push bp mov bp,sp ; ; { ; printf("foo1() = %d\n", foo1(10)); ; push 10 call near ptr FOO1 push ax push offset DGROUP:s@ call near ptr _printf add sp,4 ; ; printf("foo2() = %d\n", foo2(10, 20)); ; push 10 push 20 call near ptr FOO2 push ax push offset DGROUP:s@+13 call near ptr _printf add sp,4 ; ; printf("foo3() = %d\n", foo3(10, 20, 30)); ; push 10 push 20 push 30 call near ptr FOO3 push ax push offset DGROUP:s@+26 call near ptr _printf add sp,4 ; ; printf("foo4() = %d\n", foo4(10, 20, 30, 40)); ; push 10 push 20 push 30 push 40 call near ptr FOO4 push ax push offset DGROUP:s@+39 call near ptr _printf add sp,4 ; ; return 0; ; xor ax,ax pop bp ret ; ; } ; pop bp ret _main endp ?debug C E9 ?debug C FA00000000 _TEXT ends _DATA segment word public 'DATA' s@ label byte db 'foo1() = %d' db 10 db 0 db 'foo2() = %d' db 10 db 0 db 'foo3() = %d' db 10 db 0 db 'foo4() = %d' db 10 db 0 _DATA ends _TEXT segment byte public 'CODE' _TEXT ends _s@ equ s@ extrn _printf:near extrn FOO1:near extrn FOO2:near extrn FOO3:near extrn FOO4:near public _main extrn __setargv__:far end ||< #navi_footer|C言語系|