x86の呼び出し規則


X86_calling_conventions

、x86アーキテクチャマイクロプロセッサをプログラミングするときに使用される呼び出し規則について説明します。
呼び出し規則は、呼び出されたコードのインターフェースを記述します。
アトミック(スカラー)パラメーター、または複雑なパラメーターの個々の部分が割り当てられる順序
パラメーターの受け渡し方法(スタックにプッシュされるか、レジスターに配置されるか、または両方の組み合わせ)
呼び出された関数が呼び出し元のために保持する必要のあるレジスター(別名:呼び出し先保存レジスターまたは不揮発性レジスター)
関数呼び出しのスタックの準備とその後の復元のタスクが、呼び出し元と呼び出し先の間でどのように分割されるか
これは、プログラミング言語タイプへのサイズとフォーマットの割り当てと密接に関連しています。もう1つの密接に関連するトピックは、名前マングリングです。これは、コード内のシンボル名がリンカーによって使用されるシンボル名にどのようにマップされるかを決定します。呼び出し規則、型表現、および名前マングリングはすべて、アプリケーションバイナリインターフェイス(ABI)として知られているものの一部です。
多くの場合、さまざまなコンパイラーがこれらの規則を実装する方法には微妙な違いがあるため、さまざまなコンパイラーによってコンパイルされたコードをインターフェースすることはしばしば困難です。一方、API標準として使用される規則(stdcallなど)は非常に均一に実装されています。

コンテンツ
1 歴史的背景
2 発信者のクリーンアップ
2.1 cdecl
2.1.1 バリエーション
2.2 システムコール 2.3 optlink
3 呼び出し先のクリーンアップ
3.1 パスカル 3.2 stdcall 3.3 Microsoft fastcall 3.43.4 Microsoft vectorcall 3.5 ボーランド登録 3.6 ワトコムレジスター 3.7 TopSpeed /クラリオン/ JPI 3.8 セーフコール
4 発信者または着信者のクリーンアップ
4.1 thiscall
5 登録保存
5.1 呼び出し元が保存した(揮発性)レジスタ 5.2 Callee-saved(不揮発性)レジスタ
6 x86-64の呼び出し規則
6.1 Microsoftx64呼び出し規約 6.2 System V AMD64 ABI
7 x86呼び出し規則のリスト
8 参考文献
8.1 脚注 8.2 その他の情報源
9 参考文献

歴史的背景
マイクロコンピューターが登場する前は、機械メーカーは通常、いくつかのプログラミング言語用のオペレーティングシステムとコンパイラーを提供していました。呼び出し規約の各プラットフォーム用(S)は、メーカーのプログラミングツールで定義されたものでした。
CommodorePetおよびAppleII以前の初期のマイクロコンピューターには、通常、OSまたはコンパイラーが付属していませんでした。IBM PCは、 WindowsにMicrosoftのフォアランナー、ディスクオペレーティングシステム(付属のDOS)が、それはコンパイラが付属していませんでした。IBM PC互換機の唯一のハードウェア標準は、Intelプロセッサ(8086、80386)とIBMが出荷した文字通りのハードウェアによって定義されました。ハードウェア拡張機能とすべてのソフトウェア標準(BIOS呼び出し規約を除く)は、市場競争にさらされました。
多数の独立したソフトウェア会社が、オペレーティングシステム、多くのプログラミング言語用のコンパイラ、およびアプリケーションを提供していました。さまざまな要件、歴史的慣行、およびプログラマーの創造性に基づいて、多くの場合、相互に排他的な、多くの異なる呼び出しスキームが企業によって実装されました。
IBM互換市場のシェイクアウト後、Microsoftオペレーティングシステムとプログラミングツール(規則が異なる)が優勢でしたが、BorlandやNovellなどの第2層企業、およびGCCなどのオープンソースプロジェクトは依然として独自の標準を維持していました。ベンダーと製品間の相互運用性の規定が最終的に採用され、実行可能な規則を選択する問題が単純化されました。

発信者のクリーンアップ
これらの規則では、呼び出し元はスタックから引数をクリーンアップします。

cdecl
CDECL(の略Cの宣言は)のために、Microsoftのコンパイラに由来すること呼び出し規約であるCプログラミング言語とは、のために多くのCコンパイラで使用されているx86アーキテクチャ。 cdeclでは、サブルーチン引数がスタックに渡されます。整数値とメモリアドレスは、EAXの中に返されるレジスタST0に浮動小数点値を、X87登録してレジスタEAX、ECX、およびEDXは呼び出し元で保存され、残りは呼び出し先で保存されます。x87 ST7へ浮動小数点レジスタST0は、新しい関数を呼び出すとき(ポップ又は解放)が空でなければならず、ST7へST1は、関数を出るに空でなければなりません。ST0は、値を返すために使用されない場合も空である必要が
Cプログラミング言語のコンテキストでは、関数の引数は右から左の順序でスタックにプッシュされます。つまり、最後の引数が最初にプッシュされます。
次のCソースコードスニペットについて考えてみます。
int callee (int 、 int 、 int );INT 発信者(ボイド){ 戻り 呼び出し先(1 、 2 、 3 ) + 5 。}
上のx86、それは以下の生じる可能性がありますアセンブリコード(インテル構文):
発信者: ; 新しいコールフレームを作成し ます; (一部のコンパイラは、代わりに「enter」命令を生成する場合があります) push ebp
; 古い呼び出しフレームの保存 のmov
EBPを、 ESP 。新しい呼び出しフレームを初期化します ; 逆に、プッシュ呼び出し引数 ; (一部のコンパイラは、スタックポインタから必要なスペースを減算する場合があります 。;次に、各引数を直接書き込みます。以下を参照して ; ‘enter’命令も同様のことを実行できます) ; sub esp、12: ‘enter’命令は私たちのためにこれを行うことができます ; mov 、3:またはmov 、3 ; mov 、2:またはmov 、2 ; mov 、1:またはmov 、1 push 3 push 2 push 1 call callee ; サブルーチンを呼び出す ‘callee’ add
esp 、 12 ; フレームからの呼び出しの引数を削除し 、追加 EAX 、 5 。サブルーチンの結果を変更し
ます; (eaxは呼び出し先の戻り値である
ため、ローカル変数に移動する必要はありません) ; 古いコールフレームを復元し ます; (一部のコンパイラは、代わりに「leave」命令を生成する場合があります) mov
esp 、 ebp ; ほとんどの呼び出し規則では、ebpを呼び出し先に保存するように指示されてい
ます。つまり、呼び出し先に電話した後も保持されます。
; したがって、それでもスタックフレームの開始を指します。
; 確認する必要があり
ます; ただし、呼び出し先はebpを変更(または復元)しません
。したがって、確認する必要があり
ます; それはこのない呼び出し規約使用する ポップ EBPを
。古いコールフレームを復元する ret
; 戻る
呼び出し元は、関数呼び出しが戻った後にスタックをクリーンアップします。
CDECL呼び出し規約は、通常、x86のCのためのデフォルトの呼び出し規則でコンパイラ多くのコンパイラが自動的に使用呼び出し規約を変更するオプションを提供するものの、。関数をcdeclとして手動で定義するために、次の構文をサポートするものも
return_type __cdecl func_name ();

バリエーション
cdeclの解釈にはいくつかのバリエーションがその結果、異なるオペレーティングシステムプラットフォーム用および/または異なるコンパイラによってコンパイルされたx86プログラムは、両方とも「cdecl」規則を使用し、基盤となる環境を呼び出さない場合でも、互換性がない可能性が
値を返す方法に関して、一部のコンパイラは、レジスタペアEAX:EDXで2レジスタ以下の長さの単純なデータ構造、および例外ハンドラによる特別な処理を必要とするより大きな構造とクラスオブジェクト(たとえば、定義されたコンストラクタ、デストラクタ、または割り当て)がメモリに返されます。「メモリ内」を渡すために、呼び出し元はメモリを割り当て、非表示の最初のパラメータとしてそのメモリへのポインタを渡します。呼び出し先はメモリにデータを入力してポインタを返し、戻るときに非表示のポインタをポップします。
ではLinuxでは、GCCはセット事実上の規則を呼び出すための標準を。GCCバージョン4.5以降、関数を呼び出すときにスタックを16バイト境界に整列させる必要があります(以前のバージョンでは4バイトの整列のみが必要でした)。
cdeclのバージョンは、i386システム用のSystem VABIで説明されています。

システムコール
これは、引数が右から左にプッシュされるという点でcdeclに似ています。EAX、ECX、およびEDXは保持されません。ダブルワード単位のパラメータリストのサイズはALで渡されます。
Syscallは、32ビットOS / 2APIの標準の呼び出し規約です。

optlink
引数は右から左にプッシュされます。最初の(左端の)3つの引数はEAX、EDX、およびECXで渡され、最大4つの浮動小数点引数がST0からST3で渡されますが、それらのスペースはスタックの引数リストで予約されています。結果はEAXまたはST0で返されます。レジスタEBP、EBX、ESI、およびEDIは保持されます。
Optlinkがで使用されているIBMのVisualAgeのコンパイラ。

呼び出し先のクリーンアップ
これらの規則では、呼び出し先はスタックから引数をクリーンアップします。これらの規則を利用する関数は、戻った後にスタックを巻き戻すため、ASMコードで簡単に認識できます。x86 ret命令では、呼び出し元に戻った後に解放するスタックバイト数を指定するオプションの16ビットパラメーターを使用できます。このようなコードは次のようになります。 ret 12 fastcallまたはregisterというタイトルの規則は標準化されておらず、コンパイラベンダーに応じて実装が異なります。通常、レジスタベースの呼び出し規則は、レジスタに1つ以上の引数を渡します。これにより、呼び出しに必要なメモリアクセスの数が減り、通常は高速になります。

パスカル
Borland Pascalプログラミング言語の呼び出し規約に基づいて、パラメーターは左から右の順序(cdeclの反対)でスタックにプッシュされ、呼び出し先はスタックからパラメーターを削除する責任が
結果を返すことは次のように機能します。
順序値は、AL(8ビット値)、AX(16ビット値)、EAX(32ビット値)、またはDX:AX(16ビットシステムでは32ビット値)で返されます。
実数値はDX:BX:AXで返されます。
浮動小数点(8087)の値がST0に返されます。
ポインタは、32ビットシステムではEAXで、16ビットシステムではAXで返されます。
文字列は、@ Resultシンボルが指す一時的な場所に返されます。
この呼び出し規約は、OS / 2 1.x、Microsoft Windows 3.x、およびBorlandDelphiバージョン1.xの16ビットAPIで一般的でした。Windows APIの最新バージョンはstdcallを使用します。これは、Pascal規則のように、呼び出し先がスタックを復元しますが、パラメーターは右から左にプッシュされるようになりました。

stdcall
stdcall 呼び出し規約は、呼び出し先がスタックのクリーンアップを担当するPascal呼び出し規約のバリエーションですが、_cdecl呼び出し規約のように、パラメーターは右から左の順序でスタックにプッシュされます。レジスタEAX、ECX、およびEDXは、関数内で使用するように指定されています。戻り値はEAXレジスタに格納されます。
STDCALLは、マイクロソフトの標準的な呼び出し規約でのWin32 APIとのためのオープンWatcomのC ++。

Microsoft fastcall Microsoft __fastcall規則(別名
__msfastcall)は、ECXとEDXに適合する最初の2つの引数(左から右に評価)を渡します。残りの引数は、右から左にスタックにプッシュされます。コンパイラがIA64またはAMD64用にコンパイルする場合、コンパイラは__fastcallキーワードを無視し、
代わりに1つの64ビット呼び出し規約を使用します。
これは非常に一般的な呼び出し規約であるため、GCC、Clang、ICCなどの他のコンパイラもfastcallをサポートしています。
次のCスニペットについて考えてみます。
__attribute __ ((fastcall )) void printnums (int num1 、 int num2 、 int num3 ){ printf (”送信した数値は次のとおりです:%d%d%d” 、 num1 、 num2 、 num3 ); }INT メイン(){ printnums (1 、 2 、 3 )。 0を返す ; }
main関数のx86逆コンパイルは(Intel構文で)次のようになります。
メイン: ; スタックセットアップ プッシュ EBPの MOV形式 EBP 、 ESP 押し 3 。即時3(3番目の引数がスタックにプッシュされます) mov edx 、 0x2 ; イミディエート2(2番目の引数)がedxレジスタにコピーされます。 mov ecx 、 0x1 ; イミディエート1(最初の引数)がecxレジスタにコピーされます。 printnums mov eax 、0を呼び出し ます。0を返すretnを残す
最初の2つの引数は左から右の順序で渡され、3番目の引数はスタックにプッシュされます。スタックのクリーンアップは呼び出し先によって実行されるため、スタックのクリーンアップはありません。呼び出し先関数の分解は次のとおりです。
printnums : ; スタックセットアップ プッシュ EBP MOV EBP 、 ESP サブ ESP 、 0x08の MOV 、 ECX 。x86では、ecx =最初の引数。 mov 、 edx ; arg2 push [ ebp + 0x08 ]
; arg3はスタックにプッシュされます。 プッシュ
; arg2はプッシュ プッシュ
; arg1はプッシュされます プッシュ 0x8065d67
; “送信した番号は%d%d%dです” call printf ; スタックのクリーンアップを 追加し 、ESP 、 0x10の NOPの 休暇 RETN 0x04のを
2つの引数がレジスタを通過し、1つのパラメータのみがスタックにプッシュされたため、x86システムではintのサイズが4バイトであるため、プッシュされた値はretn命令によってクリアされます。

Microsoft vectorcall
Visual Studio 2013で、Microsoftは、ゲーム、グラフィック、ビデオ/オーディオ、およびコーデックの開発者からの効率性の懸念に応えて、__ vectorcall呼び出し規約を導入
しました。このスキームでは、より大きなベクトル型( float、 double、 __ m128、
__ m256)をスタックではなくレジスターに渡すことができます。
IA-32およびx64コードの場合、
__ vectorcallはそれぞれ__fastcallおよび元のx64呼び出し規則に似てい
ますが、SIMDレジスタを使用したベクトル引数の受け渡しをサポートするように拡張されています。IA-32では、整数値は通常どおり渡され、最初の6つのSIMD(XMM / YMM 0-5)レジスタは、実際の位置に関係なく、最大6つの浮動小数点、ベクトル、またはHVA値を左から右に順番に保持します。たとえば、それらの間に現れるint引数によって引き起こされます。ただし、x64では、元のx64規則の規則が引き続き適用されるため、XMM / YMM0-5は、浮動小数点、ベクトル、またはHVA引数が1番目から6番目までの場合にのみ保持されます。
__vectorcallは、同じ6つのレジスタを使用して、最大4つの同一のベクトルタイプのみで構成される複合タイプ(構造体)である同次ベクトル集約(HVA)値を渡すためのサポートを追加します。レジスタがベクトル型引数に割り当てられると、未使用のレジスタが左から右にHVA引数に割り当てられます。ポジショニングルールは引き続き適用されます。結果のベクトルタイプとHVA値は、最初の4つのXMM / YMMレジスタを使用して返されます。
clangコンパイラとIntelC ++コンパイラもvectorcallを実装しています。 Intel C ++コンパイラには、__ regcallと呼ばれる同様の以前の規則があり
ました。clangでもサポートされています。

ボーランド登録
引数を左から右に評価し、EAX、EDX、ECXを介して3つの引数を渡します。残りの引数も左から右にスタックにプッシュされます。これはDelphiの32ビットコンパイラのデフォルトの呼び出し規約であり、レジスタとして知られています。この呼び出し規約は、EmbarcaderoのC ++ Builderでも使用されており、__ fastcallと呼ばれます。このコンパイラでは、Microsoftのfastcallを__msfastcallとして使用できます。
GCCとClangは__stdcall、regparmfunction属性または-mregparm=3switchを使用して、同様の呼び出し規約を使用するように作成できます。(スタックの順序が逆になります。)これを使用して呼び出し元のクリーンアップバリアントを作成しcdeclたり、SSEレジスタを使用するように拡張したりすることもできます。 Acdeclベースのバージョンは、バージョン2.6.20以降のi386上のLinuxカーネルで使用されている(2007年2月リリース)。

ワトコムレジスター
Watcomは、nullにエイリアスする場合を除いて、__ fastcallキーワードをサポートしレジスタ呼び出し規約は、コマンドラインスイッチで選択できます。(ただし、IDAは均一性のためにとにかく__fastcallを使用します。)
最大4つのレジスタがEAX、EDX、EBX、ECXの順序で引数に割り当てられます。引数は、左から右にレジスタに割り当てられます。いずれかの引数をレジスタに割り当てることができない場合(たとえば、大きすぎる場合)、その引数と後続のすべての引数がスタックに割り当てられます。スタックに割り当てられた引数は、右から左にプッシュされます。名前は、接尾辞の下線を追加することによってマングルされます。
可変個引数関数は、Watcomスタックベースの呼び出し規約にフォールバックします。
Watcom C / C ++コンパイラは、ユーザーが独自の呼び出し規約を指定できるようにする
#pragma aux ディレクティブも使用します。マニュアルに記載されているように、「この方法を必要とするユーザーはごくわずかですが、必要な場合は命の恩人になる可能性があります」。

TopSpeed /クラリオン/ JPI
最初の4つの整数パラメーターは、レジスタeax、ebx、ecx、およびedxで渡されます。浮動小数点パラメーターは、浮動小数点スタック(レジスタst0、st1、st2、st3、st4、st5、およびst6)で渡されます。構造パラメータは常にスタックに渡されます。レジスタが使い果たされた後、追加のパラメータがスタックに渡されます。整数値はeaxで返され、ポインターはedxで返され、浮動小数点型はst0で返されます。

セーフコール
ではデルファイとFree Pascalの上のMicrosoft Windows、safecallの呼び出し規約カプセル化COM(コンポーネントオブジェクトモデル)エラー処理は、このような例外は、呼び出し側に漏洩していないが、中に報告されているHRESULTのCOM / OLEの要求に応じて、戻り値。Delphiコードからsafecall関数を呼び出すと、Delphiは返されたHRESULTも自動的にチェックし、必要に応じて例外を発生させます。
safecall呼び出し規約はstdcall呼び出し規約と同じですが、例外がEAXの呼び出し元に(FS:ではなく)HResultとして返され、関数の結果が参照によってスタック上で次のように渡される点が異なります。それは最後の「out」パラメータでしたが。DelphiからDelphi関数を呼び出す場合、例外はEAXで返されますが、呼び出し元によって自動的に適切な例外に変換されるため、この呼び出し規約は他の呼び出し規約と同じように表示されます。他の言語で作成されたCOMオブジェクトを使用する場合、HResultsは例外として自動的に発生し、Get関数の結果はパラメーターではなく結果になります。safecallを使用してDelphiでCOMオブジェクトを作成する場合、例外は通常どおり発生する可能性がありますが、他の言語ではHResultとして表示されるため、HResultについて心配する必要はありません。
関数 function_name (a : DWORD ): DWORD ; セーフコール;
結果を返し、通常のDelphi関数のように例外を発生させますが、次のように値と例外を渡します。
function function_name (a : DWORD ; out Result : DWORD ): HResult ; stdcall ;
発信者または着信者のクリーンアップ編集

thiscall
この呼び出し規約は、C ++の非静的メンバー関数を呼び出すために使用されます。コンパイラと、関数が可変数の引数を使用するかどうかに応じて、この呼び出しには2つの主要なバージョンが使用されます。
GCCコンパイラの場合、thiscallはほぼ同じですCDECL:呼び出し側がスタックをきれいにし、パラメータは右から左へ順に渡されます。違いは、関数プロトタイプの最初のパラメーターであるかのように、最後にスタックにプッシュされるthisポインターの追加です。
Microsoft Visual C ++コンパイラでは、thisポインタはECXで渡され、スタックをクリーンアップするのは呼び出し先であり、このコンパイラのCおよびWindowsAPI関数で使用されるstdcall規則を反映しています。関数が可変数の引数を使用する場合、スタックをクリーンアップするのは呼び出し元です(cdeclを参照)。
thiscall呼び出し規約が明示的にのみ、マイクロソフトのVisual C ++ 2005以降で指定することができます。他のコンパイラでは、thiscallはキーワードではありません。(ただし、IDAなどの逆アセンブラはそれを指定する必要がしたがって、IDAはこれにキーワード__thiscallを使用します。)

登録保存
呼び出し規約のもう1つの部分は、サブルーチン呼び出し後にレジスターがその値を保持することが保証されていることです。

呼び出し元が保存した(揮発性)レジスタ
大多数のコンパイラが準拠しているIntelABIによると、EAX、EDX、およびECXは、プロシージャまたは関数内で自由に使用でき、保存する必要はありません。
名前が示すように、これらの汎用レジスタは通常、一時的な(揮発性の)情報を保持しており、任意のサブルーチンで上書きできます。
したがって、サブルーチン呼び出し後に値を復元する場合は、これらの各レジスタをスタックにプッシュするのは呼び出し元の責任です。

Callee-saved(不揮発性)レジスタ
他のレジスタは、呼び出し間で保持する必要がある長期的な値(不揮発性)を保持するために使用されます。
つまり、呼び出し元がプロシージャコールを実行すると、呼び出し先が戻った後、それらのレジスタが同じ値を保持することが期待できます。
したがって、呼び出し元に戻る前に、それらを保存(最初にプッシュ)および復元(それに応じてポップ)することは、呼び出し先の責任になります。前の場合と同様に、この方法は、呼び出し先が変更したレジスターでのみ実行する必要が

x86-64の呼び出し規則
x86-64の呼び出し規則では、追加のレジスタスペースを利用して、レジスタでより多くの引数を渡します。また、互換性のない呼び出し規則の数が削減されました。一般的に使用されているものは2つ

Microsoftx64呼び出し規約
Microsoftx64呼び出し規約 は、WindowsおよびプリブートUEFI(x86-64のロングモードの場合)に準拠しています。最初の4つの引数はレジスタに配置されます。つまり、整数、構造体、またはポインター引数の場合はRCX、RDX、R8、R9(この順序で)、浮動小数点引数の場合はXMM0、XMM1、XMM2、XMM3を意味します。追加の引数がスタックにプッシュされます(右から左)。64ビット以下の場合、整数の戻り値(x86と同様)がRAXに返されます。浮動小数点の戻り値はXMM0で返されます。長さが64ビット未満のパラメーターはゼロ拡張されません。上位ビットはゼロ化されません。
整数と一致するサイズの構造体と共用体が渡され、整数であるかのように返されます。それ以外の場合、引数として使用されると、ポインターに置き換えられます。特大の構造体の戻りが必要な場合、呼び出し元が提供したスペースへの別のポインターが最初の引数として付加され、他のすべての引数が1桁右にシフトします。
Windowsコンテキストでx64アーキテクチャ用にコンパイルする場合(MicrosoftまたはMicrosoft以外のツールを使用するかどうかに関係なく)、stdcall、thiscall、cdecl、およびfastcallはすべてこの規則を使用するように解決されます。
Microsoft x64の呼び出し規約では、関数を呼び出す直前にスタックに32バイトの「シャドウスペース」を割り当て(実際に使用されるパラメーターの数に関係なく)、呼び出し後にスタックをポップするのは呼び出し側の責任です。シャドウスペースは、RCX、RDX、R8、およびR9 をこぼすために使用されますが、パラメーターが4つ未満の関数であっても、すべての関数で使用できるようにする必要が
レジスタRAX、RCX、RDX、R8、R9、R10、R11は、揮発性(呼び出し元が保存)と見なされます。
レジスタRBX、RBP、RDI、RSI、RSP、R12、R13、R14、およびR15は、不揮発性(呼び出し先保存)と見なされます。
たとえば、5つの整数引数を取る関数は、レジスターの1番目から4番目を取り、5番目はシャドウスペースの上にプッシュされます。したがって、呼び出された関数が入力されると、スタックは(昇順で)リターンアドレス、シャドウスペース(32バイト)、5番目のパラメーターで構成されます。
ではx86-64では、Visual Studio 2008の店舗がXMM6とXMM7(だけでなく、XMM15通じXMM8)での浮動小数点数。したがって、x86-64の場合、ユーザー作成のアセンブリ言語ルーチンはXMM6とXMM7を保持する必要があります(ユーザー作成のアセンブリ言語ルーチンがXMM6とXMM7を保持する必要がなかったx86と比較して)。つまり、x86からx86-64に移植する場合、関数の前後にXMM6とXMM7を保存/復元するには、ユーザー作成のアセンブリ言語ルーチンを更新する必要が
Visual Studio 2013以降、Microsoftはx64規則を拡張する__vectorcall呼び出し規則を導入し
ました。

System V AMD64 ABI
呼び出し規約のSystem V AMD64 ABIが上に続いているのSolaris、Linuxでは、FreeBSDでは、MacOSの、やUnixとの間で事実上の標準Unixライクなオペレーティングシステムです。OpenVMSのx86-64の上の標準の呼び出しは、後方互換性のために必要ないくつかの拡張とシステムV ABIに基づいています。最初の6つの整数またはポインター引数は、レジスタRDI、RSI、RDX、RCX、R8、R9(ネストされた関数の場合、R10は静的チェーンポインターとして使用されます)で渡されますが、XMM0、XMM1 、XMM2、XMM3、XMM4、XMM5、XMM6、およびXMM7は、最初の浮動小数点引数に使用されます。 Microsoft x64の呼び出し規約と同様に、追加の引数がスタックに渡されます。最大64ビットの整数戻り値がRAXに格納され、最大128ビットの値がRAXおよびRDXに格納されます。浮動小数点の戻り値は、同様にXMM0とXMM1に格納されます。幅の広いYMMおよびZMMレジスタは、XMMが存在する場合、その代わりに幅の広い値を渡したり返したりするために使用されます。、55
呼び出し先がレジスタRBX、RSP、RBP、およびR12〜R15を使用する場合は、呼び出し元に制御を戻す前に、元の値を復元する必要が他のすべてのレジスタは、それらの値を保持したい場合、呼び出し元が保存する必要が
リーフノード関数(他の関数を呼び出さない関数)の場合、128バイトのスペースが関数のスタックポインターのすぐ下に格納されます。このスペースはレッドゾーンと呼ばれます。このゾーンは、シグナルハンドラーや割り込みハンドラーによって破壊されることはありません。したがって、コンパイラはこのゾーンを利用してローカル変数を保存できます。コンパイラは、このゾーンを利用することにより、関数の開始時に一部の命令(RSP、RBPの調整)を省略できます。ただし、他の機能がこのゾーンを破壊する可能性がしたがって、このゾーンはリーフノード機能にのみ使用する必要がgccおよびclang提供-mno-red-zone無効に赤ゾーンの最適化にフラグを。
呼び出し先が可変個引数関数の場合、ベクトルレジスタで関数に渡される浮動小数点引数の数は、ALレジスタで呼び出し元によって提供される必要が
Microsoftの呼び出し規約とは異なり、シャドウスペースは提供され関数エントリでは、戻りアドレスはスタックの7番目の整数引数に隣接しています。

x86呼び出し規則のリスト
これは、x86の呼び出し規則のリストです。これらは、主にC / C ++コンパイラ(特に以下の64ビット部分)を対象とした規則であり、したがって主に特殊なケースです。他の言語では、実装で他の形式や規則を使用する場合が
建築 名前 オペレーティングシステム、コンパイラ パラメーター スタックのクリーンアップ ノート
レジスター スタック順序8086 cdecl
RTL(C)
発信者
パスカル
LTR(パスカル)
呼び出し先
fastcall(非会員)
マイクロソフト
AX、DX、BX
LTR(パスカル)
呼び出し先 BXでポインタを返します。
fastcall(メンバー関数)
マイクロソフト AX、DX LTR(パスカル)
呼び出し先 thisスタックの下位アドレス。AXでポインタを返します。 fastcall ターボC
AX、DX、BX
LTR(パスカル)
呼び出し先 thisスタックの下位アドレス。スタックの上位アドレスにポインタを返します。
ワトコム
AX、DX、BX、CX
RTL(C)
呼び出し先 SIでポインタを返します。IA-32 cdecl
Unixライク(GCC)
RTL(C)
発信者 構造体/クラスを返すとき、呼び出し元のコードはスペースを割り当て、スタック上の非表示パラメーターを介してこのスペースへのポインターを渡します。呼び出された関数は、このアドレスに戻り値を書き込みます。バグのため、スタックは16バイト境界に整列しました。 cdecl マイクロソフト
RTL(C)
発信者
構造体/クラスを返す場合、
32ビット以下のプレーンオールドデータ(POD)の戻り値はEAXレジスタにあります
サイズが33〜64ビットのPOD戻り値は、EAX:EDXレジスタを介して返されます。
非PODの戻り値または64ビットより大きい値の場合、呼び出し元のコードはスペースを割り当て、スタック上の非表示パラメーターを介してこのスペースへのポインターを渡します。呼び出された関数は、このアドレスに戻り値を書き込みます。
4バイト境界に整列されたスタック。 stdcall マイクロソフト
RTL(C)
呼び出し先 GCCでもサポートされています。 fastcall マイクロソフト ECX、EDX RTL(C)
呼び出し先 メンバー関数でない場合は、スタックにポインタを返します。GCCでもサポートされています。
登録 DelphiとFreePascal EAX、EDX、ECX
LTR(パスカル)
呼び出し先 thiscall Windows(Microsoft Visual C ++) ECX RTL(C)
呼び出し先 メンバー関数のデフォルト。 vectorcall Windows(Microsoft Visual C ++)
ECX、EDX、 MM0–5 
RTL(C)
呼び出し先 fastcallから拡張されました。ICCとClangでもサポートされています。
Watcomコンパイラ
EAX、EDX、EBX、ECX
RTL(C)
呼び出し先 ESIでポインタを返します。 x86-64 Microsoftx64の呼び出し規約
Windows(Microsoft Visual C ++、GCC、Intel C ++コンパイラ、Delphi)、UEFI
RCX / XMM0、RDX / XMM1、R8 / XMM2、R9 / XMM3
RTL(C)
発信者 16バイトに整列されたスタック。スタック上の32バイトのシャドウスペース。指定された8つのレジスターは、パラメーター1から4にのみ使用できます。C++クラスの場合、非表示thisパラメーターは最初のパラメーターであり、RCXで渡されます。 vectorcall Windows(Microsoft Visual C ++、Clang、ICC)
RCX / MM0、RDX / MM1、R8 / MM2、R9 / MM3 + MM4–5
RTL(C)
発信者
MSx64から拡張。
System V AMD64 ABI
Solaris、Linux、BSD、macOS、OpenVMS(GCC、Intel C ++コンパイラ、Clang、Delphi)
RDI、RSI、RDX、RCX、R8、R9、 MM0–7
RTL(C)
発信者 16バイト境界に整列されたスタック。スタックの下の128バイトのレッドゾーン。カーネルインターフェイスは、RDI、RSI、RDX、R10、R8、およびR9を使用します。C ++では、thisが最初のパラメーターです。

参考文献

脚注
^ Agner Fog(2010-02-16)。さまざまなC ++コンパイラおよびオペレーティングシステムの呼び出し規則 (PDF)。
^ Boyne Pollard、ジョナサン(2010)。「関数呼び出し規則の生成」。頻繁に与えられる答え。
^ 「GCCBugzilla–バグ40838-gccはスタックが整列していると想定すべきではありません」。2009年。
^ 「SYSTEMVアプリケーションバイナリインターフェイスIntel386アーキテクチャプロセッササプリメント第4版」(PDF)。
^ “__stdcall(C ++)”。MSDN。マイクロソフト。2008年4月10日にオリジナルからアーカイブされました。2019-02-13を取得しました。
^ “__ fastcall”。MSDN 。
^ オーセ、ウーウェ。「gcc属性の概要:関数fastcall」。ohse.de 。
^ 「『ベクトル呼び出し規約をご紹介』」。MSDN。2013年7月11日。
^ “__ vectorcall”。MSDN 。
^ 「Clangの属性:呼び出し規則」。Clangドキュメント。
^ 「_ vectorcallおよび__regcallの謎を解き明かす」。software.intel.com。2017年6月7日。
^ 「プログラム制御:レジスタ規則」。docwiki.embarcadero.com。2010-06-01 。
^ “_fastcall、__ fastcall”。docwiki.embarcadero.com。
^ “__ msfastcall”。docwiki.embarcadero.com。
^ 「x86関数属性」。GNUコンパイラコレクション(GCC)の使用。
^ 「i386:常にregparmを有効にする」。
^ 「Calling_Conventions:Specifying_Calling_Conventions_the_Watcom_Way」。openwatcom.org。2010-04-27 。
^ “x64ソフトウェア規則:呼び出し規則”。msdn.microsoft.com。2010 。
^ 「x64アーキテクチャ」。msdn.microsoft.com。
^ 「x64呼び出し規約:戻り値」。docs.microsoft.com 。
^ 「x64ソフトウェアの規則-スタック割り当て」。Microsoft 。
^ “発信者/着信者が保存したレジスタ”。MicrosoftDocs。マイクロソフト。
^ 「x86-64コードモデル」。Mac開発者ライブラリ。Apple Inc.2016-03-10のオリジナルからアーカイブ。OS Xのx86-64環境には、ユーザースペースコードのコードモデルが1つしかありません。これは、x86-64 System VABIで定義されている小さなPICモデルに最もよく似ています。
^ 「VSIOpenVMSCalling Standard」(PDF)。vmssoftware.com。2020年5月。
^ Michael Matz; JanHubička; アンドレアス・イェーガー; et al。、eds。(2018-01-28)。「SystemVアプリケーションバイナリインターフェイス:AMD64アーキテクチャプロセッササプリメント(LP64およびILP32プログラミングモデル付き)バージョン1.0」(PDF)。1.0。
^ Borland C / C ++バージョン3.1ユーザーガイド(PDF)。ボーランド。1992. pp。158、189–191。
^ 「使用法の登録」。MicrosoftDocs。Microsoft 。

その他の情報源
「SYSTEMVアプリケーションバイナリインターフェイスIntel386アーキテクチャプロセッササプリメント」 (PDF)(第4版)。サンタクルスオペレーション社1997-03-19。
Nemanja Trifunovic(2001-07-22)。ショーン・ユーイングトン(編)。「召集条約の謎を解き明かす」。コードプロジェクト。
スティーブンJ.フリードル。「Intelx86関数呼び出し規則—アセンブリビュー」。SteveFriedlのUnixwiz.netの技術的なヒント。
「VisualStudio2010 — Visual C ++呼び出し規約」。MSDNライブラリ。マイクロソフト。2010年。
アンドレアスジョンソン(2005-02-13)。「x86プラットフォームでの呼び出し規則」。
レイモンド・チェン(2004-01-02)。「コンベンションの呼び出しの歴史、パート1」。古い新しいもの。
レイモンド・チェン(2004-01-07)。「コンベンションの呼び出しの歴史、パート2」。古い新しいもの。
レイモンド・チェン(2004-01-08)。「コンベンションの呼び出しの歴史、パート3」。古い新しいもの。
レイモンド・チェン(2004-01-13)。「コンベンションの呼び出しの歴史、パート4:ia64」。古い新しいもの。
レイモンド・チェン(2004-01-14)。「呼び出し規則の履歴、パート5; amd64」。古い新しいもの。

参考文献
ジョナサンデボインポラード(2010)。「関数呼び出し規則の生成」。頻繁に与えられる答え。
キップR.アーバイン(2011)。「高度な手順(第8章)」。x86プロセッサ用のアセンブリ言語(第6版)。プレンティスホール。ISBN 978-0-13-602212-1。
Borland C / C ++バージョン3.1ユーザーガイド (PDF)。ボーランド。1992. pp。158、189–191。
トーマス・ラウアー(1995)。「新しい__stdcall呼び出しシーケンス」。Win32への移植:Windowsの32ビットの未来のためにアプリケーションを準備するためのガイド。スプリンガー。ISBN 978-0-387-94572-9。