#navi_header|C言語系| OpenWatcom で特に呼び出し規約を指定しない場合のデフォルトの呼び出し規約。 ''OpenWatcomでは、main()関数は強制的に __watcall 呼び出し規約になる(他の呼び出し規約を指定しても、無視される)。'' (ただし実験した結果であって、マニュアル・ドキュメント上でこの点について記載されているかは未確認) #more|| ---- #outline|| ---- * OpenWatcom Compiler(16bit) ※サンプルコードは [[620]] の callee.c, caller.c を使用。 : 指定方法 : #block||> ※明示的に指定したい場合 int __watcall foobar(); typedef int (__watcall *ptr)(); ||< : コンパイラオプション : "-ecw", ''C言語で他の呼び出し規約が指定されていない場合のデフォルト'' : 装飾名 : 関数名 + "_" OpenWatcomのDOS用コンパイラ(wcc.exe)で今回のサンプルコードをコンパイルしたところ、次のような引数の渡し方になっていることが分かった。 - 左から4つまでの引数は、 ''左から順にAX, DX, BX, CXレジスタ経由で'' 渡される。 - 左から5つ目以降の引数は、 ''右から左へ'' スタックへ積まれる。 - スタックのクリーンアップは、関数(callee)側で "RET imm16" 命令により実現している。 AX, BXまで使われている点が驚きだが、コード中でEAXやEBXを使うようなより実際のコードの場合、どのように変化するかまでは不明。 コンパイル&リンク&実行 #pre||> > wcc -od -d0 -ecw callee.c > wcc -od -d0 -ecw caller.c > wcl -fe=watcall16.exe caller.obj callee.obj > watcall16.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_: 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) #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,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) ※サンプルコードは [[620]] の callee.c, caller.c を使用。 : 指定方法 : #block||> ※明示的に指定したい場合 int __watcall foobar(); typedef int (__watcall *ptr)(); ||< : コンパイラオプション : "-ecw", ''C言語で他の呼び出し規約が指定されていない場合のデフォルト'' : 装飾名 : 関数名 + "_" OpenWatcomのDOS用コンパイラ(wcc386.exe)で今回のサンプルコードをコンパイルしたところ、次のような引数の渡し方になっていることが分かった。 - 左から4つまでの引数は、 ''左から順にEAX, EDX, EBX, ECXレジスタ経由で'' 渡される。 - 左から5つ目以降の引数は、 ''右から左へ'' スタックへ積まれる。 - スタックのクリーンアップは、関数(callee)側で "RET imm16" 命令により実現している。 EAX, EBXまで使われている点が驚きだが、コード中でEAXやEBXを使うようなより実際のコードの場合、どのように変化するかまでは不明。 コンパイル&リンク&実行 #pre||> > wcc386 -od -d0 -ecw callee.c > wcc386 -od -d0 -ecw caller.c > wcl386 -fe=watcall32.exe caller.obj callee.obj > watcall32.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 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) #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 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 ||< #navi_footer|C言語系|