関数呼び出し規約

Light C で作成した関数をアセンブラなどの他言語のルーチンとリンクする場合は、関数の呼び出し規約を合わせる必要があります。ここでは、Light C で使用される呼び出し規約について説明します。

なお、実際の正確な呼び出し規約を確認するには、-fa で生成されるアセンブラ コードを調べると効果的です。次は、C のソース ファイルと、そこから生成されたアセンブラ コードの例です。

// C のソース
int subr( int a, char b, long c ) {
	a = 1;
	b = 1;
	c = 1;
	return( 4 );
}
; アセンブラ コード
public _subr
_subr proc near ; line 1
push bp
mov bp,sp
mov ax,0
call __stack_chk
a$ equ [bp+4] ; size=2
b$ equ [bp+6] ; size=1
c$ equ [bp+8] ; size=4
mov word ptr [a$],1h ; line 3
mov byte ptr [b$],1h ; line 4
mov word ptr [c$],1h ; line 5
mov word ptr [c$+2],0h
mov ax,4h ; line 6
mov sp,bp
pop bp
ret
_subr endp

アセンブラ ルーチンとのリンク」も参照してください。

引数

Light C では、すべての引数がスタック経由で関数に渡されます。 引数は 2 バイト単位でスタックに置かれます。つまり、1 バイトの char 変数は 2 バイト、3 バイトの構造体は 4 バイトのスタック領域を占有します。

関数内では、通常、BP レジスタを使ってスタック上の引数にアクセスします。

戻り値

戻り値は、サイズに応じてレジスタまたはスタック経由で返されます。次のようになります。

サイズ返される方法
char 1 AL レジスタ経由
int 2 AX レジスタ経由
long 4 DX:AX レジスタ経由
float 4 DX:AX レジスタ経由
double 8 スタック経由
near ポインタ 2 AX レジスタ経由
far ポインタ 4 DX:AX レジスタ経由
構造体 1 AL レジスタ経由
構造体 2 AX レジスタ経由
構造体 4 DX:AX レジスタ経由
構造体 3, 5〜 スタック経由

引数の順序とアンダースコア (_)

関数には、関数名と引数の順序を指定するために、次の修飾子を指定できます。

修飾子「_」の付加スタックに引数を積む順序
(なし) あり 後から
syscall なし 後から
stdcall あり 前から
pascal なし 前から
cdecl_r あり 後から
syscall_r なし 後から
stdcall_r あり 前から
pascal_r なし 前から

これらは、API などの特殊な関数を宣言する場合、または特殊なルーチンから呼び出される関数を定義する場合に指定します。
int syscall funcA(int a1, int a2); // プロトタイプ宣言で
void pascal funcB(int a1, int a2) { // 関数定義で
  ...
}

引数が前からスタックに積まれる stdcall および pascal では、関数の呼び出し側ではなく、関数側がスタックから引数を除去します。

V1.42 以降では、引数を除去する側だけを逆にする cdecl_rsyscall_rstdcall_rpascal_r が追加されました。

interrupt 修飾子については、「割り込みハンドラ」を参照してください。