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

C言語系/呼び出し規約/x86/fortran (v3)

C言語系/呼び出し規約/x86/fortran (v3)

C言語系 / 呼び出し規約 / x86 / fortran (v3)
id: 620 所有者: msakamoto-sf    作成日: 2010-03-17 10:33:21
カテゴリ: Assembler C言語 Windows 

2010年現在、OpenWatcomでサポートされている。

2010年の時点のMSDNによると、現在は "__fortran" 呼び出し規約はサポートされていない。(obsoleted)

ただし、サポートされていないのはあくまでも "__fortran" という宣言であり、次のMSDNを見る限りでは "__stdcall" と "__cdecl" が Fortran <> C,C++ との間で使えるようである。

  • Mixed-Language Programming Topics

"__cdecl", "__stdcall" 共に引数を渡す順序は "右→左" である。ではFortran <> C,C++間はそれでOKかと思いきや、以下の記事では「"__pascal"呼び出し規約と同じ」とあり、これだけ見ると「左→右」の順序と読み取れる。

MSDNの記事の場合は"Visual Studio 6.0"時代の内容であるし、"The Old New Thing"とともにFortran処理系を特に指定していない。従って、実際にどのFortranでどの呼び出し規約をC,C++との間で使えるのかは、手持ちの資料だけでは正確には何も言えない。

2010-12-24追記:
"The Old New Thing"からFORTRANとCの相互運用について新しい記事が登場した。FORTRANでは関数の引数をリファレンス渡しにする必要があったり、配列のインデックスが1始まりになっていたり、複素数の扱い方などが紹介されている。



サンプルコード

callee.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; }
int foo5(int a, int b, int c, int d, int e) { return a + b + c + d + e; }
int foo6(int a, int b, int c, int d, int e, int f) { return a + b + c + d + e + f; }

caller.c (呼ぶ main() 側)

#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);
extern int foo5(int a, int b, int c, int d, int e);
extern int foo6(int a, int b, int c, int d, int e, int f);
 
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));
    printf("foo5() = %d\n", foo5(10, 20, 30, 40, 50));
    printf("foo6() = %d\n", foo6(10, 20, 30, 40, 50, 60));
    return 0;
}

OpenWatcom Compiler(16bit)

指定方法
int __fortran foobar();
typedef int (__fortran *ptr)();
コンパイラオプション
"-ecr"
装飾名
関数名の英字が全て大文字に変換される。

OpenWatcomのDOS用コンパイラ(wcc.exe)で今回のサンプルコードをコンパイルしたところ、次のような引数の渡し方になっていることが分かった。

  • 左から4つまでの引数は、左から順にAX, DX, BX, CXレジスタ経由で渡される。
  • 左から5つ目以降の引数は、右から左へスタックへ積まれる。
  • スタックのクリーンアップは、関数(callee)側で "RET imm16" 命令により実現している。

AX, BXまで使われている点が驚きだが、コード中でEAXやEBXを使うようなより実際のコードの場合、どのように変化するかまでは不明。

コンパイル&リンク&実行

> wcc -od -d0 -ecr callee.c
> wcc -od -d0 -ecr caller.c
> wcl -fe=fortran.exe caller.obj callee.obj
> fortran.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

callee.c のアセンブラ出力(callee.asm)

.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:
    push        ax 
    mov         ax,2 
    call        near ptr __STK 
    pop         ax 
    shl         ax,1 
    ret         
FOO2:
    push        ax 
    mov         ax,2 
    call        near ptr __STK 
    pop         ax 
    add         ax,dx 
    ret         
FOO3:
    push        ax 
    mov         ax,2 
    call        near ptr __STK 
    pop         ax 
    add         ax,dx 
    add         ax,bx 
    ret         
FOO4:
    push        ax 
    mov         ax,2 
    call        near ptr __STK 
    pop         ax 
    add         ax,dx 
    add         ax,bx 
    add         ax,cx 
    ret         
FOO5:
    push        ax 
    mov         ax,4 
    call        near ptr __STK 
    pop         ax 
    push        bp 
    mov         bp,sp 
    add         ax,dx 
    add         ax,bx 
    add         ax,cx 
    add         ax,word ptr 4[bp] 
    pop         bp 
    ret         2 
FOO6:
    push        ax 
    mov         ax,4 
    call        near ptr __STK 
    pop         ax 
    push        bp 
    mov         bp,sp 
    add         ax,dx 
    add         ax,bx 
    add         ax,cx 
    add         ax,word ptr 4[bp] 
    add         ax,word ptr 6[bp] 
    pop         bp 
    ret         4 
_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)

.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,0aH 
    call        near ptr __STK 
    pop         ax 
    push        bx 
    push        cx 
    mov         ax,0aH 
    call        near ptr FOO1 
    push        ax 
    mov         ax,offset DGROUP:L$1 
    push        ax 
    call        near ptr printf_ 
    add         sp,4 
    mov         dx,14H 
    mov         ax,0aH 
    call        near ptr FOO2 
    push        ax 
    mov         ax,offset DGROUP:L$2 
    push        ax 
    call        near ptr printf_ 
    add         sp,4 
    mov         bx,1eH 
    mov         dx,14H 
    mov         ax,0aH 
    call        near ptr FOO3 
    push        ax 
    mov         ax,offset DGROUP:L$3 
    push        ax 
    call        near ptr printf_ 
    add         sp,4 
    mov         cx,28H 
    mov         bx,1eH 
    mov         dx,14H 
    mov         ax,0aH 
    call        near ptr FOO4 
    push        ax 
    mov         ax,offset DGROUP:L$4 
    push        ax 
    call        near ptr printf_ 
    add         sp,4 
    mov         ax,32H 
    push        ax 
    mov         cx,28H 
    mov         bx,1eH 
    mov         dx,14H 
    mov         ax,0aH 
    call        near ptr FOO5 
    push        ax 
    mov         ax,offset DGROUP:L$5 
    push        ax 
    call        near ptr printf_ 
    add         sp,4 
    mov         ax,3cH 
    push        ax 
    mov         ax,32H 
    push        ax 
    mov         cx,28H 
    mov         bx,1eH 
    mov         dx,14H 
    mov         ax,0aH 
    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)

指定方法
int __fortran foobar();
typedef int (__fortran *ptr)();
コンパイラオプション
"-ecr"
装飾名
関数名の英字が全て大文字に変換される。

OpenWatcomのDOS用コンパイラ(wcc386.exe)で今回のサンプルコードをコンパイルしたところ、次のような引数の渡し方になっていることが分かった。

  • 左から4つまでの引数は、左から順にEAX, EDX, EBX, ECXレジスタ経由で渡される。
  • 左から5つ目以降の引数は、右から左へスタックへ積まれる。
  • スタックのクリーンアップは、関数(callee)側で "RET imm16" 命令により実現している。

EAX, EBXまで使われている点が驚きだが、コード中でEAXやEBXを使うようなより実際のコードの場合、どのように変化するかまでは不明。

コンパイル&リンク&実行

> wcc386 -od -d0 -ecr callee.c
> wcc386 -od -d0 -ecr caller.c
> wcl386 -fe=fortran.exe caller.obj callee.obj
> fortran.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

callee.c のアセンブラ出力(callee.asm)

.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 
    add         eax,eax 
    ret         
FOO2:
    push        4 
    call        near ptr FLAT:__CHK 
    add         eax,edx 
    ret         
FOO3:
    push        4 
    call        near ptr FLAT:__CHK 
    add         eax,edx 
    add         eax,ebx 
    ret         
FOO4:
    push        4 
    call        near ptr FLAT:__CHK 
    add         eax,edx 
    add         eax,ebx 
    add         eax,ecx 
    ret         
FOO5:
    push        4 
    call        near ptr FLAT:__CHK 
    add         eax,edx 
    add         ebx,eax 
    lea         eax,[ebx+ecx] 
    add         eax,dword ptr 4[esp] 
    ret         4 
FOO6:
    push        4 
    call        near ptr FLAT:__CHK 
    add         eax,edx 
    add         eax,ebx 
    add         eax,ecx 
    add         eax,dword ptr 4[esp] 
    add         eax,dword ptr 8[esp] 
    ret         8 
_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)

.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        14H 
    call        near ptr FLAT:__CHK 
    push        ebx 
    push        ecx 
    mov         eax,0aH 
    call        near ptr FLAT:FOO1 
    push        eax 
    push        offset FLAT:L$1 
    call        near ptr FLAT:printf_ 
    add         esp,8 
    mov         edx,14H 
    mov         eax,0aH 
    call        near ptr FLAT:FOO2 
    push        eax 
    push        offset FLAT:L$2 
    call        near ptr FLAT:printf_ 
    add         esp,8 
    mov         ebx,1eH 
    mov         edx,14H 
    mov         eax,0aH 
    call        near ptr FLAT:FOO3 
    push        eax 
    push        offset FLAT:L$3 
    call        near ptr FLAT:printf_ 
    add         esp,8 
    mov         ecx,28H 
    mov         ebx,1eH 
    mov         edx,14H 
    mov         eax,0aH 
    call        near ptr FLAT:FOO4 
    push        eax 
    push        offset FLAT:L$4 
    call        near ptr FLAT:printf_ 
    add         esp,8 
    push        32H 
    mov         ecx,28H 
    mov         ebx,1eH 
    mov         edx,14H 
    mov         eax,0aH 
    call        near ptr FLAT:FOO5 
    push        eax 
    push        offset FLAT:L$5 
    call        near ptr FLAT:printf_ 
    add         esp,8 
    push        3cH 
    push        32H 
    mov         ecx,28H 
    mov         ebx,1eH 
    mov         edx,14H 
    mov         eax,0aH 
    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


プレーンテキスト形式でダウンロード
現在のバージョン : 3
更新者: msakamoto-sf
更新日: 2010-12-24 16:10:10
md5:b8303b50efe7680b9d159eb9ecdec504
sha1:6d76d86e57bcbc5fee707893da7a93f31ad9c9f5
コメント
コメントを投稿するにはログインして下さい。