"PASCAL"はヘッダーファイルで定義された呼び出し規約で、"__pascal"呼び出し規約のことではない。
実際にどの呼び出し規約("__stdcall", "__cdecl", "__pascal", ...)になるかは、OS/コンパイラによって異なってくるので、使用する場合は注意が必要。
ただし、2010年現在の Win32 APIプラットフォームにおいては基本的に PASCAL == "__stdcall" と考えて良い。
VC++2008, Borland C++ Compiler, OpenWatcom(32bit), MinGW-gcc 共に、PASCALは"__stdcall"にdefineされている。
VC++2008/Borland C++ Compiler/MinGW-gccで "PASCAL" を使うには、Windows用のヘッダーファイルをincludeする必要がある。今回は "windows.h" をincludeした。
windows.hをincludeしない場合、VC++2008/Borland C++ Compilerの両方で関数宣言の構文エラーとなりコンパイルに失敗する。
#include <stdio.h> #include <windows.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; }
プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__stdcall" にdefineされている事が分かる。
MSDN上では "obsoleted" となっており、"WINAPI"の方を使うよう推奨されている。
コンパイル&リンク&実行
> cl /FAs /TC /Od /nologo /c big_pascal.c > link /SUBSYSTEM:CONSOLE /NOLOGO /OUT:big_pascal.exe big_pascal.obj > big_pascal.exe foo() = 150
プリプロセス結果を生成:
> cl /P /TC /Od /nologo /c big_pascal.c
プリプロセス結果:
#line 3 "big_pascal.c" int __stdcall 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; }
; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01
TITLE C:\in_vitro\c\cc_vc\big_pascal.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
_DATA SEGMENT
$SG78588 DB 'foo() = %d', 0aH, 00H
_DATA ENDS
PUBLIC _foo@20
; Function compile flags: /Odtp
; File c:\in_vitro\c\cc_vc\big_pascal.c
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
_d$ = 20 ; size = 4
_e$ = 24 ; size = 4
_foo@20 PROC
; 5 : { return a + b + c + d + e; }
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]
add eax, DWORD PTR _e$[ebp]
pop ebp
ret 20 ; 00000014H
_foo@20 ENDP
_TEXT ENDS
PUBLIC _main
EXTRN _printf:PROC
; Function compile flags: /Odtp
_TEXT SEGMENT
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_main PROC
; 7 : int main(int argc, char *argv[]) {
push ebp
mov ebp, esp
; 8 : printf("foo() = %d\n", foo(10, 20, 30, 40, 50));
push 50 ; 00000032H
push 40 ; 00000028H
push 30 ; 0000001eH
push 20 ; 00000014H
push 10 ; 0000000aH
call _foo@20
push eax
push OFFSET $SG78588
call _printf
add esp, 8
; 9 : return 0;
xor eax, eax
; 10 : }
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__stdcall" にdefineされている事が分かる。
アセンブラコードを生成
> bcc32 -S big_pascal.c
コンパイル&実行
> bcc32 big_pascal.c > big_pascal.exe foo() = 150
プリプロセス結果を生成:
> cpp32 big_pascal.c
プリプロセス結果:
/* big_pascal.c 3: */ /* big_pascal.c 4: */int __stdcall foo(int a, int b, int c, int d, int e) /* big_pascal.c 5: */{ return a + b + c + d + e; } /* big_pascal.c 6: */ /* big_pascal.c 7: */int main(int argc, char *argv[]) { /* big_pascal.c 8: */printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); /* big_pascal.c 9: */return 0; /* big_pascal.c 10: */}
.386p
ifdef ??version
if ??version GT 500H
.mmx
endif
endif
model flat
ifndef ??version
?debug macro
endm
endif
?debug S "big_pascal.c"
?debug T "big_pascal.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'
foo proc near
?live1@0:
;
; int PASCAL foo(int a, int b, int c, int d, int e)
;
push ebp
mov ebp,esp
;
; { return a + b + c + d + e; }
;
@1:
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+12]
add eax,dword ptr [ebp+16]
add eax,dword ptr [ebp+20]
add eax,dword ptr [ebp+24]
@3:
@2:
pop ebp
ret 20
foo endp
_main proc near
?live1@48:
;
; int main(int argc, char *argv[]) {
;
push ebp
mov ebp,esp
;
; printf("foo() = %d\n", foo(10, 20, 30, 40, 50));
;
@4:
push 50
push 40
push 30
push 20
push 10
call foo
push eax
push offset s@
call _printf
add esp,8
;
; return 0;
;
xor eax,eax
;
; }
;
@6:
@5:
pop ebp
ret
_main endp
_TEXT ends
_DATA segment dword public use32 'DATA'
s@ label byte
; s@+0:
db "foo() = %d",10,0
align 4
_DATA ends
_TEXT segment dword public use32 'CODE'
_TEXT ends
public foo
public _main
extrn __setargv__:near
extrn _printf:near
?debug C 9F757569642E6C6962
?debug C 9F757569642E6C6962
?debug D "C:\in_vitro\apps\borland\bcc55\include\imm.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\mcx.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winsvc.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\commdlg.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\oleauto.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\propidl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\oaidl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\msxml.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\servprov.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\oleidl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\urlmon.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\cguid.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\objidl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\unknwn.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\search.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\stdlib.h" 10521 10272
?debug D "C:\in_vitro\apps\borland\bcc55\include\objbase.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\ole2.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\prsht.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winspool.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winsmcrd.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winioctl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnsip.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcndr.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\wtypes.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winscard.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winefs.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\wincrypt.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\qos.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winsock2.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winperf.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\shellapi.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcasync.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnterr.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnsi.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcdcep.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcdce.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpc.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\nb30.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\mmsystem.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\lzexpand.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\dlgs.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\ddeml.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\dde.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\cderr.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winnetwk.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winreg.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winver.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\wincon.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winnls.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\tvout.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winuser.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack1.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\wingdi.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winerror.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winbase.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack8.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack2.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\poppack.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack4.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\mem.h" 10521 10272
?debug D "C:\in_vitro\apps\borland\bcc55\include\_loc.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\locale.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\_str.h" 10521 10272
?debug D "C:\in_vitro\apps\borland\bcc55\include\string.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\guiddef.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\basetsd.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\mbctype.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\ctype.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winnt.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\windef.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\stdarg.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\excpt.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\windows.h" 10339 10240
?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 "big_pascal.c" 15473 34993
end
プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__pascal" にdefineされている事が分かる。
コンパイル&リンク&実行
> set INCLUDE=%WATCOM%\h;%WATCOM%\h\win > wcl big_pascal.c
アセンブラ生成:
> wdis -a -l=big_pascal.asm big_pascal.obj
プリプロセス結果を生成:
> wcl -pcl -fo big_pascal.i big_pascal.c
プリプロセス結果:
#line 2 "big_pascal.c" 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; }
.387
PUBLIC FOO
PUBLIC main_
EXTRN __STK:BYTE
EXTRN printf_: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
FOO:
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
main_:
push ax
mov ax,10H
call near ptr __STK
pop ax
push bx
push cx
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 FOO
push ax
mov ax,offset DGROUP:L$1
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, 28H, 29H, 20H, 3dH, 20H
DB 25H, 64H, 0aH, 0
CONST ENDS
CONST2 SEGMENT WORD PUBLIC USE16 'DATA'
CONST2 ENDS
_DATA SEGMENT WORD PUBLIC USE16 'DATA'
_DATA ENDS
END
プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__stdcall" にdefineされている事が分かる。
コンパイル&リンク&実行
> set INCLUDE=%WATCOM%\h;%WATCOM%\h\nt > wcl386 big_pascal.c
アセンブラ生成:
> wdis -a -l=big_pascal.asm big_pascal.obj
プリプロセス結果を生成:
> wcl386 -pcl -fo big_pascal.i big_pascal.c
プリプロセス結果:
#line 2 "big_pascal.c" int __stdcall 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; }
.387
.386p
.model flat
PUBLIC `_foo@20`
PUBLIC main_
EXTRN __CHK:BYTE
EXTRN printf_: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
`_foo@20`:
push 4
call near ptr FLAT:__CHK
mov eax,dword ptr 4[esp]
add eax,dword ptr 8[esp]
add eax,dword ptr 0cH[esp]
add eax,dword ptr 10H[esp]
add eax,dword ptr 14H[esp]
ret 14H
main_:
push 1cH
call near ptr FLAT:__CHK
push ecx
push 32H
push 28H
push 1eH
push 14H
push 0aH
call near ptr FLAT:`_foo@20`
push eax
push offset FLAT:L$1
call near ptr FLAT:printf_
add esp,8
xor eax,eax
pop ecx
ret
_TEXT ENDS
CONST SEGMENT DWORD PUBLIC USE32 'DATA'
L$1:
DB 66H, 6fH, 6fH, 28H, 29H, 20H, 3dH, 20H
DB 25H, 64H, 0aH, 0
CONST ENDS
CONST2 SEGMENT DWORD PUBLIC USE32 'DATA'
CONST2 ENDS
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
_DATA ENDS
END
プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__attribute__()"版stdcall にdefineされている事が分かる。
コンパイル&リンク&実行
$ gcc -O0 -Wall --save-temps -o big_pascal big_pascal.c $ big_pascal.exe foo() = 150
プリプロセス結果:
# 3 "big_pascal.c" 2 int __attribute__((__stdcall__)) 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; }
.file "big_pascal.c" .text .globl _foo@20 .def _foo@20; .scl 2; .type 32; .endef _foo@20: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax addl 16(%ebp), %eax addl 20(%ebp), %eax addl 24(%ebp), %eax popl %ebp ret $20 .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii "foo() = %d\12\0" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $24, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -4(%ebp) movl -4(%ebp), %eax call __alloca call ___main movl $50, 16(%esp) movl $40, 12(%esp) movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call _foo@20 subl $20, %esp movl %eax, 4(%esp) movl $LC0, (%esp) call _printf movl $0, %eax leave ret .def _printf; .scl 2; .type 32; .endef