#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) ※サンプルコードは [[620]] の callee.c, caller.c を使用。 : 指定方法 : #block||> int __pascal foobar(); typedef int (__pascal *ptr)(); ||< : コンパイラオプション : "-ecp" : 装飾名 : 関数名の英字が全て大文字に変換される。 コンパイル&リンク&実行 #pre||> > wcc -od -d0 -ecp callee.c > wcc -od -d0 -ecp caller.c > wcl -fe=pascal16.exe caller.obj callee.obj > pascal16.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100 foo5() = 150 foo6() = 210 ||< アセンブラ生成 #pre||> > wdis -a -l=callee.asm callee.obj > wdis -a -l=caller.asm caller.obj ||< ** callee.c のアセンブラ出力(callee.asm) #pre||> .387 PUBLIC FOO1 PUBLIC FOO2 PUBLIC FOO3 PUBLIC FOO4 PUBLIC FOO5 PUBLIC FOO6 EXTRN __STK:BYTE EXTRN _small_code_:BYTE DGROUP GROUP CONST,CONST2,_DATA _TEXT SEGMENT BYTE PUBLIC USE16 'CODE' ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP FOO1: mov ax,4 call near ptr __STK push bp mov bp,sp mov ax,word ptr 4[bp] shl ax,1 pop bp ret 2 FOO2: mov ax,4 call near ptr __STK push bp mov bp,sp mov ax,word ptr 6[bp] add ax,word ptr 4[bp] pop bp ret 4 FOO3: mov ax,4 call near ptr __STK push bp mov bp,sp mov ax,word ptr 8[bp] add ax,word ptr 6[bp] add ax,word ptr 4[bp] pop bp ret 6 FOO4: mov ax,4 call near ptr __STK push bp mov bp,sp mov ax,word ptr 0aH[bp] add ax,word ptr 8[bp] add ax,word ptr 6[bp] add ax,word ptr 4[bp] pop bp ret 8 FOO5: mov ax,4 call near ptr __STK push bp mov bp,sp mov ax,word ptr 0cH[bp] add ax,word ptr 0aH[bp] add ax,word ptr 8[bp] add ax,word ptr 6[bp] add ax,word ptr 4[bp] pop bp ret 0aH FOO6: mov ax,4 call near ptr __STK push bp mov bp,sp mov ax,word ptr 0eH[bp] add ax,word ptr 0cH[bp] add ax,word ptr 0aH[bp] add ax,word ptr 8[bp] add ax,word ptr 6[bp] add ax,word ptr 4[bp] pop bp ret 0cH _TEXT ENDS CONST SEGMENT WORD PUBLIC USE16 'DATA' CONST ENDS CONST2 SEGMENT WORD PUBLIC USE16 'DATA' CONST2 ENDS _DATA SEGMENT WORD PUBLIC USE16 'DATA' _DATA ENDS END ||< ** caller.c のアセンブラ出力(caller.asm) #pre||> .387 PUBLIC main_ EXTRN __STK:BYTE EXTRN FOO1:BYTE EXTRN printf_:BYTE EXTRN FOO2:BYTE EXTRN FOO3:BYTE EXTRN FOO4:BYTE EXTRN FOO5:BYTE EXTRN FOO6:BYTE EXTRN __argc:BYTE EXTRN _small_code_:BYTE EXTRN _cstart_:BYTE DGROUP GROUP CONST,CONST2,_DATA _TEXT SEGMENT BYTE PUBLIC USE16 'CODE' ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP main_: push ax mov ax,12H call near ptr __STK pop ax push bx push cx mov ax,0aH push ax call near ptr FOO1 push ax mov ax,offset DGROUP:L$1 push ax call near ptr printf_ add sp,4 mov ax,0aH push ax mov ax,14H push ax call near ptr FOO2 push ax mov ax,offset DGROUP:L$2 push ax call near ptr printf_ add sp,4 mov ax,0aH push ax mov ax,14H push ax mov ax,1eH push ax call near ptr FOO3 push ax mov ax,offset DGROUP:L$3 push ax call near ptr printf_ add sp,4 mov ax,0aH push ax mov ax,14H push ax mov ax,1eH push ax mov ax,28H push ax call near ptr FOO4 push ax mov ax,offset DGROUP:L$4 push ax call near ptr printf_ add sp,4 mov ax,0aH push ax mov ax,14H push ax mov ax,1eH push ax mov ax,28H push ax mov ax,32H push ax call near ptr FOO5 push ax mov ax,offset DGROUP:L$5 push ax call near ptr printf_ add sp,4 mov ax,0aH push ax mov ax,14H push ax mov ax,1eH push ax mov ax,28H push ax mov ax,32H push ax mov ax,3cH push ax call near ptr FOO6 push ax mov ax,offset DGROUP:L$6 push ax call near ptr printf_ add sp,4 xor ax,ax pop cx pop bx ret _TEXT ENDS CONST SEGMENT WORD PUBLIC USE16 'DATA' L$1: DB 66H, 6fH, 6fH, 31H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$2: DB 66H, 6fH, 6fH, 32H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$3: DB 66H, 6fH, 6fH, 33H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$4: DB 66H, 6fH, 6fH, 34H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$5: DB 66H, 6fH, 6fH, 35H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$6: DB 66H, 6fH, 6fH, 36H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 CONST ENDS CONST2 SEGMENT WORD PUBLIC USE16 'DATA' CONST2 ENDS _DATA SEGMENT WORD PUBLIC USE16 'DATA' _DATA ENDS END ||< * OpenWatcom Compiler(32bit) ※サンプルコードは [[620]] の callee.c, caller.c を使用。 : 指定方法 : #block||> int __pascal foobar(); typedef int (__pascal *ptr)(); ||< : コンパイラオプション : "-ecp" : 装飾名 : 関数名の英字が全て大文字に変換される。 コンパイル&リンク&実行 #pre||> > wcc386 -od -d0 -ecp callee.c > wcc386 -od -d0 -ecp caller.c > wcl386 -fe=pascal32.exe caller.obj callee.obj > pascal32.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100 foo5() = 150 foo6() = 210 ||< アセンブラ生成 #pre||> > wdis -a -l=callee.asm callee.obj > wdis -a -l=caller.asm caller.obj ||< ** callee.c のアセンブラ出力(callee.asm) #pre||> .387 .386p .model flat PUBLIC FOO1 PUBLIC FOO2 PUBLIC FOO3 PUBLIC FOO4 PUBLIC FOO5 PUBLIC FOO6 EXTRN __CHK:BYTE DGROUP GROUP CONST,CONST2,_DATA _TEXT SEGMENT BYTE PUBLIC USE32 'CODE' ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP FOO1: push 4 call near ptr FLAT:__CHK mov eax,dword ptr 4[esp] add eax,eax ret 4 FOO2: push 4 call near ptr FLAT:__CHK mov eax,dword ptr 8[esp] add eax,dword ptr 4[esp] ret 8 FOO3: push 4 call near ptr FLAT:__CHK mov eax,dword ptr 0cH[esp] add eax,dword ptr 8[esp] add eax,dword ptr 4[esp] ret 0cH FOO4: push 4 call near ptr FLAT:__CHK mov eax,dword ptr 10H[esp] add eax,dword ptr 0cH[esp] add eax,dword ptr 8[esp] add eax,dword ptr 4[esp] ret 10H FOO5: push 4 call near ptr FLAT:__CHK mov eax,dword ptr 14H[esp] add eax,dword ptr 10H[esp] add eax,dword ptr 0cH[esp] add eax,dword ptr 8[esp] add eax,dword ptr 4[esp] ret 14H FOO6: push 4 call near ptr FLAT:__CHK mov eax,dword ptr 18H[esp] add eax,dword ptr 14H[esp] add eax,dword ptr 10H[esp] add eax,dword ptr 0cH[esp] add eax,dword ptr 8[esp] add eax,dword ptr 4[esp] ret 18H _TEXT ENDS CONST SEGMENT DWORD PUBLIC USE32 'DATA' CONST ENDS CONST2 SEGMENT DWORD PUBLIC USE32 'DATA' CONST2 ENDS _DATA SEGMENT DWORD PUBLIC USE32 'DATA' _DATA ENDS END ||< ** caller.c のアセンブラ出力(caller.asm) #pre||> .387 .386p .model flat PUBLIC main_ EXTRN __CHK:BYTE EXTRN FOO1:BYTE EXTRN printf_:BYTE EXTRN FOO2:BYTE EXTRN FOO3:BYTE EXTRN FOO4:BYTE EXTRN FOO5:BYTE EXTRN FOO6:BYTE EXTRN __argc:BYTE EXTRN _cstart_:BYTE DGROUP GROUP CONST,CONST2,_DATA _TEXT SEGMENT BYTE PUBLIC USE32 'CODE' ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP main_: push 24H call near ptr FLAT:__CHK push ebx push ecx push 0aH call near ptr FLAT:FOO1 push eax push offset FLAT:L$1 call near ptr FLAT:printf_ add esp,8 push 0aH push 14H call near ptr FLAT:FOO2 push eax push offset FLAT:L$2 call near ptr FLAT:printf_ add esp,8 push 0aH push 14H push 1eH call near ptr FLAT:FOO3 push eax push offset FLAT:L$3 call near ptr FLAT:printf_ add esp,8 push 0aH push 14H push 1eH push 28H call near ptr FLAT:FOO4 push eax push offset FLAT:L$4 call near ptr FLAT:printf_ add esp,8 push 0aH push 14H push 1eH push 28H push 32H call near ptr FLAT:FOO5 push eax push offset FLAT:L$5 call near ptr FLAT:printf_ add esp,8 push 0aH push 14H push 1eH push 28H push 32H push 3cH call near ptr FLAT:FOO6 push eax push offset FLAT:L$6 call near ptr FLAT:printf_ add esp,8 xor eax,eax pop ecx pop ebx ret _TEXT ENDS CONST SEGMENT DWORD PUBLIC USE32 'DATA' L$1: DB 66H, 6fH, 6fH, 31H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$2: DB 66H, 6fH, 6fH, 32H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$3: DB 66H, 6fH, 6fH, 33H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$4: DB 66H, 6fH, 6fH, 34H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$5: DB 66H, 6fH, 6fH, 35H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 L$6: DB 66H, 6fH, 6fH, 36H, 28H, 29H, 20H, 3dH DB 20H, 25H, 64H, 0aH, 0 CONST ENDS CONST2 SEGMENT DWORD PUBLIC USE32 'DATA' CONST2 ENDS _DATA SEGMENT DWORD PUBLIC USE32 'DATA' _DATA ENDS END ||< * 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言語系|