home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

C言語系/呼び出し規約/x86/"PASCAL"

C言語系/呼び出し規約/x86/"PASCAL"

C言語系 / 呼び出し規約 / x86 / "PASCAL"
id: 626 所有者: msakamoto-sf    作成日: 2010-03-17 17:25:54
カテゴリ: Assembler C言語 Windows 

"PASCAL"はヘッダーファイルで定義された呼び出し規約で、"__pascal"呼び出し規約のことではない。
実際にどの呼び出し規約("__stdcall", "__cdecl", "__pascal", ...)になるかは、OS/コンパイラによって異なってくるので、使用する場合は注意が必要。

ただし、2010年現在の Win32 APIプラットフォームにおいては基本的に PASCAL == "__stdcall" と考えて良い。
VC++2008, Borland C++ Compiler, OpenWatcom(32bit), MinGW-gcc 共に、PASCALは"__stdcall"にdefineされている。



サンプルコード(big_pascal.c)

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;
}

VC++2008 Express Edtion (obsoleted)

プリプロセス結果およびアセンブラ出力から、"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;
}

アセンブラ出力(big_pascal.asm)

; 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

Borland C++ Compiler

プリプロセス結果およびアセンブラ出力から、"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: */}

アセンブラ出力(big_pascal.asm)

	.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

OpenWatcom Compiler(16bit)

プリプロセス結果およびアセンブラ出力から、"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;
}

アセンブラ出力(big_pascal.asm)

.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

OpenWatcom Compiler(32bit)

プリプロセス結果およびアセンブラ出力から、"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;
}

アセンブラ出力(big_pascal.asm)

.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

GCC-3.4.5, MinGW-5.1.6, MSYS 1.0

プリプロセス結果およびアセンブラ出力から、"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;
}

アセンブラ出力(big_pascal.asm)

	.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


プレーンテキスト形式でダウンロード
現在のバージョン : 3
更新者: msakamoto-sf
更新日: 2010-03-19 20:13:04
md5:27a45baeded37804789044507b7aa922
sha1:20e4367b603e88e52d04eccec241b0210ce0d9fe
コメント
コメントを投稿するにはログインして下さい。