__pascal呼び出し規約:
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; }
#include <stdio.h> 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; }
2010年現在、VC++2008では "__pascal" 呼び出し規約はサポートされていない。(obsoleted)
実際に次のようなコード(pascal.c)をコンパイルしようとすると、関数宣言のところでエラーになり、コンパイルに失敗する。
#include <stdio.h> 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; }
コンパイル→エラー、失敗:
> 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: 構文エラー : '型'
int __pascal foobar(); typedef int (__pascal *ptr)();
アセンブラコードを生成
> bcc32 -Od -p -S callee.c > bcc32 -Od -p -S caller.c
コンパイル&リンク&実行
> 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
.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
.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
※サンプルコードは C言語系/呼び出し規約/x86/fortran の callee.c, caller.c を使用。
int __pascal foobar(); typedef int (__pascal *ptr)();
コンパイル&リンク&実行
> 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
アセンブラ生成
> wdis -a -l=callee.asm callee.obj > wdis -a -l=caller.asm caller.obj
.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
.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
※サンプルコードは C言語系/呼び出し規約/x86/fortran の callee.c, caller.c を使用。
int __pascal foobar(); typedef int (__pascal *ptr)();
コンパイル&リンク&実行
> 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
アセンブラ生成
> wdis -a -l=callee.asm callee.obj > wdis -a -l=caller.asm caller.obj
.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
.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
TC4Jで、コマンドラインからの呼び出し規約指定オプションが不明だった為、gcc系列と同様、CALLINGCONVを"-D"でdefineすることにより切り替える方式を採った。
なお、TC4Jについてはリンク&実行までは行っていない。
int __pascal foobar(); typedef int (__pascal *ptr)();
アセンブラコードを生成
> tcc -DCALLINGCONV=__pascal -S callee.c > tcc -DCALLINGCONV=__pascal -S caller.c
.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
.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