| Light C | ← → 目次 索引 |
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_r、syscall_r、stdcall_r、pascal_r が追加されました。
interrupt 修飾子については、「割り込みハンドラ」を参照してください。
| Copyright © Tama Software Ltd, 1999-2012. | ← → 目次 索引 |