C / C ++で使用できるさまざまな呼び出し規約があります:、、、stdcall
などextern
。pascal
このような呼び出し規約はいくつ利用できますか。それぞれの意味は何ですか。これらを説明するリンクはありますか?
6 に答える
簡単な答え: cdecl、stdcall、および fastcall を使用します。ファーストコールはほとんど使いません。stdcall は、Windows API 関数を呼び出すために使用されます。
詳細な回答 (ウィキペディアから盗みました):
cdecl - cdecl では、サブルーチン引数がスタックで渡されます。整数値とメモリ アドレスは EAX レジスタに返され、浮動小数点値は ST0 x87 レジスタに返されます。レジスタ EAX、ECX、および EDX は呼び出し側で保存され、残りは呼び出し先で保存されます。x87 浮動小数点レジスタ ST0 から ST7 は、新しい関数を呼び出すときに空 (ポップまたは解放) する必要があり、関数を終了するときに ST1 から ST7 を空にする必要があります。値を返すために使用しない場合、ST0 も空にする必要があります。
syscall - これは、引数が右から左にプッシュされるという点で cdecl に似ています。EAX、ECX、および EDX は保持されません。ダブルワードのパラメーター・リストのサイズは、AL で渡されます。
pascal - パラメータは左から右の順序で (cdecl の逆) スタックにプッシュされ、呼び出し先は戻る前にスタックのバランスをとる責任があります。
stdcall - stdcall[4] 呼び出し規約は Pascal 呼び出し規約のバリエーションであり、呼び出し先がスタックのクリーンアップを担当しますが、パラメーターは _cdecl 呼び出しのように右から左の順序でスタックにプッシュされます。大会。レジスタ EAX、ECX、および EDX は、関数内で使用するために指定されています。戻り値は EAX レジスタに格納されます。
fastcall - __fastcall 規則 (別名 __msfastcall) は、ECX と EDX に適合する最初の 2 つの引数 (左から右に評価) を渡します。残りの引数は、スタックに右から左にプッシュされます。
ベクトル呼び出し- Visual Studio 2013 で、Microsoft は、ゲーム、グラフィック、ビデオ/オーディオ、およびコーデックの開発者からの効率に関する懸念に応えて、__vectorcall 呼び出し規約を導入しました。[7] IA-32 および x64 コードの場合、__vectorcall はそれぞれ __fastcall および元の x64 呼び出し規則に似ていますが、SIMD レジスタを使用したベクトル引数の受け渡しをサポートするように拡張されています。x64 の場合、最初の 6 つの引数のいずれかがベクトル型 (float、double、__m128、__m256 など) の場合、対応する XMM/YMM レジスタを介して渡されます。IA-32 の場合も同様に、位置に関係なく、ベクトル型の引数に対して、左から右に最大 6 つの XMM/YMM レジスタが順番に割り当てられます。さらに、__vectorcall は、同種ベクトル集約 (HVA) 値を渡すためのサポートを追加します。HVA 値は、最大 4 つの同一のベクトル型のみで構成される複合型です。同じ 6 つのレジスタを使用します。ベクトル型の引数にレジスタが割り当てられると、未使用のレジスタは位置に関係なく左から右に HVA 引数に割り当てられます。結果のベクター型と HVA 値は、最初の 4 つの XMM/YMM レジスターを使用して返されます。
safecall - Microsoft Windows 上の Delphi および Free Pascal では、safecall 呼び出し規約は COM (コンポーネント オブジェクト モデル) エラー処理をカプセル化しているため、例外は呼び出し元に漏れることはありませんが、COM/オレ。Delphi コードから safecall 関数を呼び出す場合、Delphi は返された HRESULT を自動的にチェックし、必要に応じて例外を発生させます。
safecall 呼び出し規約は stdcall 呼び出し規約と同じですが、例外は EAX で (FS:[0] ではなく) HResult として呼び出し元に返されますが、関数の結果は参照によってスタックに渡されます。それは最終的な「出力」パラメーターでしたが。Delphi から Delphi 関数を呼び出す場合、この呼び出し規約は他の呼び出し規約と同じように表示されます。例外は EAX で返されますが、呼び出し元によって適切な例外に自動的に変換されるためです。他の言語で作成された COM オブジェクトを使用する場合、HResults は自動的に例外として発生し、Get 関数の結果はパラメーターではなく結果に含まれます。Delphi で safecall を使用して COM オブジェクトを作成する場合、HResults について心配する必要はありません。
Microsoft X64 Calling Convention - Microsoft x64 Calling Convention[12][13] は、Windows およびプリブート UEFI (x86-64 のロング モード用) に準拠しています。最初の 4 つの整数またはポインター引数 (この順序で) にはレジスター RCX、RDX、R8、R9 を使用し、浮動小数点引数には XMM0、XMM1、XMM2、XMM3 を使用します。追加の引数はスタックに (右から左に) プッシュされます。整数の戻り値 (x86 と同様) は、64 ビット以下の場合、RAX で返されます。浮動小数点の戻り値は XMM0 に返されます。長さが 64 ビット未満のパラメーターはゼロ拡張されません。上位ビットはゼロになりません。
Windows コンテキストで x64 アーキテクチャ用にコンパイルする場合 (Microsoft ツールを使用するか、Microsoft 以外のツールを使用するかに関係なく)、呼び出し規則は 1 つだけです。ここで説明するものであるため、stdcall、thiscall、cdecl、fastcall などはすべて 1 つになります。そして同じ。
Microsoft x64 呼び出し規約では、関数を呼び出す直前にスタックに 32 バイトの "シャドウ スペース" を割り当て (実際に使用されるパラメーターの数に関係なく)、呼び出し後にスタックをポップするのは呼び出し元の責任です。シャドウ スペースは、RCX、RDX、R8、および R9 をスピルするために使用されますが、[14] すべての関数で使用できるようにする必要があります。
レジスタ RAX、RCX、RDX、R8、R9、R10、R11 は揮発性 (呼び出し元保存) と見なされます [15]。
レジスタ RBX、RBP、RDI、RSI、RSP、R12、R13、R14、および R15 は、不揮発性 (callee-saved) と見なされます。[15]
たとえば、5 つの整数引数を取る関数は、レジスタの 1 番目から 4 番目までを受け取り、5 番目はシャドウ スペースの一番上にプッシュされます。そのため、呼び出された関数に入ると、スタックは (昇順で) 戻りアドレス、その後にシャドウ スペース (32 バイト)、および 5 番目のパラメーターで構成されます。
x86-64 では、Visual Studio 2008 は浮動小数点数を XMM6 および XMM7 (および XMM8 から XMM15) に格納します。したがって、x86-64 の場合、ユーザー作成のアセンブリ言語ルーチンは XMM6 および XMM7 を保持する必要があります (ユーザー作成のアセンブリ言語ルーチンが XMM6 および XMM7 を保持する必要がない x86 と比較して)。つまり、x86 から x86-64 に移植する場合、関数の前後に XMM6 と XMM7 を保存/復元するように、ユーザーが作成したアセンブリ言語ルーチンを更新する必要があります。
標準 C にも標準 C++ にもそのような概念はありません。これらは特定のコンパイラ、リンカー、オペレーティング システムの機能であるため、関心のある特定のテクノロジを実際に示す必要があります。
標準 C++ には、基本的に と の 2 つがextern "C"
ありextern "C++"
ます。後者がデフォルトです。この前者は、C コードにリンクする必要がある場合に使用されます。コンパイラは、「C」と「C++」以外の文字列を定義する場合があります。たとえば、Pascal 兄弟と互換性のあるコンパイラは、extern "Pascal".
残念ながら、代わりにキーワードを発明したコンパイラもあります。このような場合は、コンパイラのドキュメントを参照してください。
これらは、呼び出しスタックにパラメーターを配置する順序と、値による呼び出しおよび/または参照による呼び出しのセマンティクスをいつ使用するかに関するものです。これらは、多言語プログラミングを簡素化することを目的としたコンパイラ固有の拡張機能です。