呼び出し規約

コンピュータサイエンスにおいて、呼び出し規約とは、サブルーチンまたは関数が呼び出し元からパラメータを受け取り、結果を返す方法に関する実装レベル(低レベル)の仕組みです。 [ 1 ] あるコードが関数を呼び出す場合、その関数にパラメータを渡す場所と方法、およびその関数から結果を返す場所と方法について設計上の選択が行われており、これらの転送は通常、特定のレジスタまたは呼び出しスタック上のスタックフレーム経由で行われます。関数呼び出しの準備と関数の完了後の環境の復元のタスクを呼び出し元と呼び出し先の間でどのように分割するかについても設計上の選択肢があります。一部の呼び出し規約は、すべての関数の呼び出し方法を指定します。これらの関数を使用するプログラム全体を正しく確実に実行できるようにするには、すべての関数呼び出しに正しい呼び出し規約を使用する必要があります。

導入

呼び出し規約は通常、アプリケーションバイナリインターフェース(ABI)の一部とみなされます。呼び出し規約は、呼び出し元と呼び出される関数間の契約と考えることもできます。 [ 1 ]

パラメータと戻り値の名前や意味は、アプリケーション・プログラミング・インターフェース(ABIではなくAPI)で定義されます。APIはABIや呼び出し規約とは関連しながらも、別の概念です。渡される構造体やオブジェクト内のメンバー名も、ABIではなくAPIの一部とみなされます。APIには、関数の呼び出し規約を指定するためのキーワードが含まれる場合があります。

呼び出し規約には通常、動的に割り当てられた構造体やオブジェクトの寿命の処理に関する情報は含まれていません。割り当てられたメモリを解放する責任がどこにあるかは、他の補足ドキュメントに記載されている場合があります。

呼び出し規約では、バイト順序や構造体のパッキングなど、構造体やオブジェクト内の項目のレイアウトが指定されることはほとんどありません。

言語によっては、呼び出し規約にエラーや例外の処理の詳細が含まれる場合(GoJavaなど)もあれば、含まれない場合もあります(C++など)。

リモート プロシージャ コールには、マーシャリングと呼ばれる類似の概念があります。

呼び出し規約は、特定のプログラミング言語の評価戦略に関連している可能性がありますが、評価戦略は通常、より高い抽象レベルで定義され、特定の言語のコンパイラの低レベルの実装の詳細ではなく、言語の一部と見なされるため、呼び出し規約はその一部とは見なされないことがほとんどです(またはその逆)。

異なる呼び出し規約

呼び出し規約は次の点で異なる場合があります。

  • パラメータが配置される場所。オプションには、レジスタ、コールスタック、両方の組み合わせ、またはその他のメモリ構造などがあります。
  • パラメータが渡される順序。オプションには、左から右、右から左、またはより複雑な順序が含まれます。
  • 可変数の引数を取る関数(可変引数関数)の処理方法。引数を順番に渡す(最初の引数が明確な位置にあると仮定)か、可変部分を配列で渡すかを選択できます。
  • 戻り値が呼び出し先から呼び出し元へどのように返されるか。スタック、レジスタ、ヒープ上に割り当てられたものへの参照など、さまざまな選択肢があります。
  • 長い値や複雑な値が、複数のレジスタに分割したり、スタック フレーム内で分割したり、メモリを参照したりして、どの程度処理されるか。
  • 呼び出し先が呼び出されたときと呼び出し先が戻ったときに、同じ値を持つことが保証されているレジスタ。これらのレジスタは保存または保持されると言われており、揮発性ではありません。
  • 関数呼び出しの準備と後片付けのタスクが、呼び出し元と呼び出し先の間でどのように分担されるか。特に、呼び出し先が終了した後、呼び出し元が処理を続行できるようにスタックフレームがどのように復元されるか。
  • 引数を記述するメタデータが渡されるかどうか、またどのように渡されるか
  • フレームポインタの以前の値が格納される場所。サブルーチン終了時にスタックフレームを復元するために使用されます。格納場所としては、コールスタック内、または特定のレジスタ内などがあります。フレームポインタが全く使用されない場合もあります。[ 2 ]
  • ルーチンの非ローカルデータアクセスの静的スコープリンクが配置される場所(通常はスタックフレーム内の1つ以上の位置ですが、汎用レジスタ、または一部のアーキテクチャでは特殊用途レジスタに配置される場合もあります)
  • オブジェクト指向言語の場合、関数のオブジェクトがどのように参照されるか

1つのプラットフォーム内での呼び出し規約

単一のプラットフォーム上で複数の呼び出し規約が使用される場合もあります。特定のプラットフォームと言語実装によっては、複数の呼び出し規約を選択できる場合があります。その理由としては、パフォーマンス、他の一般的な言語の規約への適応、様々な「コンピューティングプラットフォーム」によって課せられる制限や規約などが挙げられます。

多くのアーキテクチャでは、広く使用されている呼び出し規約が1つしか存在せず、多くの場合、これは設計者によって提案されます。SPARC 、MIPS、RISC-VなどのRISCでは、この呼び出し規約に基づいたレジスタ名がしばしば使用されます。例えば、MIPSレジスタから までは「ABI名」が付けられており、これは標準呼び出し規約におけるパラメータ渡しでの使用を反映しています。(RISC CPUには同等の汎用レジスタが多数存在するため、通常、番号以外の名前を付けるハードウェア的な理由はありません。) $4$7$a0$a3

特定のプログラム言語の呼び出し規約は、基盤となるプラットフォーム、OS、またはリンク先のライブラリの呼び出し規約とは異なる場合があります。例えば、32ビットWindowsでは、オペレーティングシステムの呼び出し規約はstdcallですが、そこで実行される多くのCプログラムはcdecl呼び出し規約を使用します。このような呼び出し規約の違いに対応するため、コンパイラでは多くの場合、特定の関数の呼び出し規約を指定するキーワードが許可されます。関数宣言には、使用する呼び出し規約を示すプラットフォーム固有のキーワードが追加されます。適切に処理されれば、コンパイラは適切な方法で関数を呼び出すコードを生成します。

一部の言語では、関数の呼び出し規約をその関数で明示的に指定できます。他の言語には呼び出し規約がありますが、その言語のユーザーには隠されているため、通常はプログラマーが考慮する必要はありません。

アーキテクチャ

x86 (32ビット)

x86アーキテクチャの32ビット版は、様々な呼び出し規約で使用されています。アーキテクチャ上のレジスタ数が少なく、また歴史的にシンプルさとコードサイズの小型化が重視されてきたため、多くのx86呼び出し規約では引数をスタックに渡します。戻り値(またはそのポインタ)はレジスタに返されます。一部の呼び出し規約では、最初の数個のパラメータにレジスタを使用することで、特に頻繁に呼び出される短く単純なリーフルーチン(つまり、他のルーチンを呼び出さないルーチン)においてパフォーマンスが向上する可能性があります。

呼び出し例:

push EAX ; レジスタの結果を渡すpush dword [ EBP + 20 ] ; メモリ変数を渡す (FASM/TASM 構文) push 3 ; 定数を渡すcall calc ; 返された結果は EAX に格納されます

典型的な呼び出し先構造:(以下の命令の一部またはすべて(retを除く)は、単純な手順で最適化によって削除される場合があります)。一部の規則では、retの代わりにplain を使用して、パラメータ空間を割り当てたままにしますret imm16。その場合、呼び出し元はadd esp,12この例のように、あるいはそれ以外の方法でESPへの変更に対処できます。

calc: push EBP ; 古いフレーム ポインターを保存します。mov EBP ESP ;新しいフレーム ポインターを取得します。sub ESP localsize ;ローカルのスタック領域を予約します。. . ; 計算を実行し、結果を EAX に残します。mov ESP EBP ; ローカルの領域を解放します。pop EBP ;古いフレーム ポインターを復元します。ret paramsize ; パラメーター領域を解放して戻ります

x86-64

x86アーキテクチャの64ビット版(x86-64、AMD64、Intel 64)では、一般的に2つの呼び出しシーケンスが使用されています。1つはMicrosoftによって定義されたもので、Windowsで使用されます。もう1つはAMD64 System V ABIで規定されており、Unix系システムや、若干の変更を加えたOpenVMSで使用されます。x86-64は32ビットx86よりも汎用レジスタの数が多いため、どちらの規約でも一部の引数はレジスタで渡されます。

アーム(A32)

標準の 32 ビットARM呼び出し規約では、16 個の汎用レジスタを次のように割り当てます。

  • r15:プログラム カウンター(命令セット仕様による)。
  • r14:リンクレジスタ。サブルーチン呼び出しで使用されるBL命令は、戻りアドレスをこのレジスタに格納します。
  • r13:スタックポインタ。「Thumb」動作モードのプッシュ/ポップ命令はこのレジスタのみを使用します。
  • r12: プロシージャ呼び出し内スクラッチ レジスタ。
  • r4 ~ r11: ローカル変数。
  • r0 ~ r3: サブルーチンに渡される引数値とサブルーチンから返される結果。

返される値の型が r0 から r3 に収まらないほど大きい場合、またはコンパイル時にそのサイズを静的に決定できない場合は、呼び出し元は実行時にその値のためのスペースを割り当て、r0 のそのスペースへのポインターを渡す必要があります。

サブルーチンは、r4からr11の内容とスタックポインタを保持する必要があります(関数プロローグでスタックに保存し、スクラッチ領域として使用し、関数エピローグでスタックから復元するなど)。特に、他のサブルーチンを呼び出すサブルーチンは、他のサブルーチンを呼び出す前に、リンクレジスタr14の戻りアドレスをスタックに保存する必要があります。ただし、このようなサブルーチンは、その値をr14に返す必要はなく、プログラムカウンタr15にロードするだけで済みます。

ARM呼び出し規約では、完全降順スタックの使用が義務付けられています。さらに、スタックポインタは常に4バイト境界に揃える必要があり、パブリックインターフェースを持つ関数呼び出しでは常に8バイト境界に揃える必要があります。[ 3 ]

この呼び出し規約により、「典型的な」 ARM サブルーチンは次の処理を実行します。

  • プロローグでは、r4 から r11 をスタックにプッシュし、r14 の戻りアドレスをスタックにプッシュします (これは単一の STM 命令で実行できます)。
  • 渡された引数 (r0 ~ r3) をローカル スクラッチ レジスタ (r4 ~ r11) にコピーします。
  • 他のローカル変数を残りのローカル スクラッチ レジスタ (r4 ~ r11) に割り当てます。
  • r0 から r3、r12、r14 は保持されないと仮定して、BL を使用して計算を実行し、必要に応じて他のサブルーチンを呼び出します。
  • 結果を r0 に格納します。
  • エピローグでは、スタックからr4をr11にプルし、戻りアドレスをプログラムカウンタr15にプルします。これは1つのLDM命令で実行できます。

アーム(A64)

64ビットARM(AArch64)呼び出し規約では、31個の汎用レジスタを次のように割り当てます。[ 4 ]

  • x31 (SP): コンテキストに応じてスタック ポインターまたはゼロ レジスタ
  • x30 (LR): プロシージャ リンク レジスタ。サブルーチンから戻るために使用されます。
  • x29 (FP):フレームポインタ
  • x19 から x28: 呼び出し側が保存されました。
  • x18 (PR): プラットフォームレジスタ。オペレーティングシステム固有の特別な目的、または呼び出し元が保存する追加のレジスタとして使用されます。
  • x16 (IP0) および x17 (IP1): プロシージャ呼び出し内スクラッチ レジスタ。
  • x9 から x15: ローカル変数、呼び出し元が保存されました。
  • x8 (XR): 間接的な戻り値アドレス。
  • x0 ~ x7: サブルーチンに渡される引数値とサブルーチンから返される結果。

xで始まるすべてのレジスタには、対応する 32 ビットレジスタがあり、その先頭にはwが付きます。したがって、32 ビットの x0 は w0 と呼ばれます。

同様に、32個の浮動小数点レジスタは次のように割り当てられる。[ 5 ]

  • v0 ~ v7: サブルーチンに渡される引数値とサブルーチンから返される結果。
  • v8 から v15: 呼び出し側で保存されますが、下位 64 ビットのみを保持する必要があります。
  • v16 から v31: ローカル変数、呼び出し元が保存されました。

RISC-V ISA

RISC-Vには、浮動小数点ありとなしの2種類の呼び出し規約が定義されています。[ 6 ]可能な限りレジスタで引数を渡します。

POWER、PowerPC、およびPower ISA

POWER 、PowerPC、およびPower ISAアーキテクチャには多数のレジスタがあるため、ほとんどの関数は単一レベルの呼び出しですべての引数をレジスタに渡すことができます追加の引数はスタックに渡され、レジスタベースの引数のためのスペースも常にスタック上に割り当てられます。これは、複数レベルの呼び出し(再帰的呼び出しなど)が使用され、レジスタを保存する必要がある場合に、呼び出された関数の利便性を確保するためです。これは、関数の引数に配列としてアクセスする必要があるなどの可変引数関数でも役立ちます。すべての手続き型言語には、単一の呼び出し規約が使用されます。 printf()

分岐リンク命令は、戻りアドレスを汎用レジスタとは別の 特別なリンク レジスタに格納します。ルーチンは、リンク レジスタを宛先アドレスとして使用する分岐命令を使用して呼び出し元に戻ります。リーフ ルーチンはリンク レジスタを保存または復元する必要はありませんが、非リーフ ルーチンは、別のルーチンを呼び出す前に戻りアドレスを保存し、戻る前に復元する必要があります。戻りアドレスの保存は、Move From Special Purpose Register 命令を使用してリンク レジスタを汎用レジスタに移動し、必要に応じてスタックに保存することによって行います。また、戻りアドレスがスタックに保存されている場合は、保存されているリンク レジスタ値を汎用レジスタにロードし、Move To Special Purpose Register 命令を使用して、保存されているリンク レジスタ値を含むレジスタをリンク レジスタに移動することによって復元します。

ミップス

O32 [ 7 ] ABIは、MIPS用のオリジナルのSystem V ABIであるため、最も広く使用されているABIです[ 8 ] O32は厳密にスタックベースであり、引数を渡すためのレジスタは4つしかありません。この遅い動作と、16個のレジスタしか持たない古風な浮動小数点モデルが相まって、他の多くの呼び出し規約の普及を促しました。このABIは1990年に形作られ、1994年以降更新されていません。32ビットMIPSのみで定義されていますが、GCCはO64と呼ばれる64ビット版を作成しました。[ 9 ]$a0-$a3

64ビット版では、シリコングラフィックスのN64 ABI(ニンテンドー64とは無関係)が最も一般的に使用されています。最も重要な改良点は、引数渡しに8つのレジスタが利用可能になったことです。また、浮動小数点レジスタの数が32に増加しています。N32と呼ばれるILP32バージョンもあり、これはx32 ABIに類似しており、32ビットポインタを使用してコードを縮小します。どちらもCPUの64ビットモードで動作します。[ 9 ]

O32をN32に似た32ビットABIに置き換えようとする試みがいくつか行われてきました。1995年の会議ではMIPS EABIが提案され、その32ビット版は非常に類似していました。[ 10 ] EABIはMIPS Technologies社にインスピレーションを与え、戻り値に引数レジスタを再利用する、より革新的な「NUBI」ABIを提案しました。[ 11 ] MIPS EABIはGCCではサポートされていますが、LLVMではサポートされていません。また、LLVMもNUBIをサポートしていません。

O32およびN32/N64のいずれの場合も、戻りアドレスはレジスタに格納されます。これは、(ジャンプ&リンク)命令または(ジャンプ&リンクレジスタ)命令$raの使用により自動的に設定されます。スタックは下方向に拡張されます。 JALJALR

SPARC

SPARCアーキテクチャは、ほとんどのRISCアーキテクチャとは異なり、レジスタウィンドウ上に構築されています。各レジスタウィンドウには24個のアクセス可能なレジスタがあり、そのうち8個は「入力」レジスタ(%i0~%i7)、8個は「ローカル」レジスタ(%l0~%l7)、8個は「出力」レジスタ(%o0~%o7)です。入力レジスタは、呼び出される関数に引数を渡すために使用され、追加の引数はスタックにプッシュする必要がありますただし、レジスタウィンドウのオーバーフロー、ローカル変数、および(32ビットSPARCの場合)構造体の値渡しを処理するために、呼び出される関数によって常に領域が割り当てられます。関数を呼び出すには、呼び出される関数の引数を「出力」レジスタに配置します。関数が呼び出されると、「出力」レジスタが「入力」レジスタになり、呼び出される関数は「入力」レジスタ内の引数にアクセスします。呼び出された関数が完了すると、戻り値が最初の「in」レジスタに配置され、呼び出された関数が戻ると最初の「out」レジスタになります。

現代のUnix系システムのほとんどが従うSystem V ABI [ 12 ]では、最初の6つの引数を「入力」レジスタ%i0から%i5に渡し、%i6をフレームポインタ、%i7を戻りアドレスとして予約しています。

IBM System/360および後継機種

IBM System/360は、ハードウェアスタックを持たない別のアーキテクチャです。以下の例は、エンタープライズ・システム・アーキテクチャ(ESA)、XPLINK、および 64 ビットz/Architectureが導入される以前のOS/360 および後継機種で使用されていたオリジナルの呼び出し規約を示しています。System/360 以降の他のオペレーティングシステムでは、異なる呼び出し規約が使用される場合があります。

呼び出しプログラム:

 LA 1,ARGS 引数リストのアドレスをロードする L 15,=V(SUB) サブルーチンアドレス1をロード BALR 14,15 呼び出されたルーチン2に分岐 ... ARGS DC A(FIRST) 第1引数のアドレス DC A(セカンド) ... DC A(THIRD)+X'80000000' 最後の引数3

呼び出されたプログラム:

SUB EQU * これはサブプログラム4のエントリポイントです

標準エントリシーケンス:

 USING *,15 5 STM 14,12,12(13) レジスタ保存6 ST 13,SAVE+4 呼び出し元の保存領域アドレスを保存する LA 12、SAVE チェーンセーブエリア ST 12,8(13) LR 13,12 ... 

標準的な戻りシーケンス:

 L 13、セーブ+4 7 LM 14,12,12(13) L 15、RETVAL 8 BR 14 発信者に戻る セーブ DS 18F セーブエリア9

注:

  1. 内部サブルーチンの場合L 15,=A(SUB)は またはを使用し、外部サブルーチンの場合は を使用します。LA 15,SUBL 15,=V(SUB)
  2. このBALR命令は、最初の引数で指定されたレジスタ(レジスタ14)に次の命令のアドレス(戻りアドレス)を格納し、レジスタ15の2番目の引数で指定されたアドレスに分岐します。BASRをサポートするモデルでは、BASRが推奨されます。24ビットモードと31ビットモードの切り替えが必要な場合は、BASSMを使用できます。
  3. 呼び出し元は、レジスタ1に引数アドレスリストのアドレスを渡します。最後のアドレスの上位ビットは、リストの終了を示すためにセットされます。そのため、この規則を使用するプログラムは31ビットアドレッシングに制限されます。
  4. 外部サブルーチンの場合は、SUB ENTRY ,の後にを組み込むSUB EQU *か、 に置き換えますSUB CSECT ,
  5. 呼び出されたルーチンのアドレスはレジスタ 15 にあります。通常、これは別のレジスタにロードされDROPUSINGレジスタ 15 がベース レジスタとして使用されなくなったことをアセンブラに通知します。
  6. このSTM命令は、レジスタ14、15、およびレジスタ0から12までの値を、呼び出し元が提供する72バイトの[ a ]領域(レジスタ13が指す保存領域)に保存します。呼び出されたルーチンは、自身が呼び出すサブルーチンで使用するために独自の保存領域を提供します。この領域のアドレスは通常、ルーチンの実行中はレジスタ13に保持されます。後続の命令は、STMこの保存領域と呼び出し元の保存領域をリンクする前方および後方チェーンを更新します。
  7. 戻りシーケンスは呼び出し元のレジスタを復元します。
  8. レジスタ15は通常、戻りコードを渡すために使用されます。示されているコードは正しくありませんが、原理を示しています。
  9. savearea呼び出されたルーチンで を静的に宣言すると、そのルーチンは再入不可能かつ非再帰的になります。再入可能なプログラムは、オペレーティング システムから取得されて返されるときに解放されるか、呼び出し元プログラムによって渡されたストレージ内の動的な を使用しますsavearea

Linuxで使用される System/390 ABI [ 13 ]およびz/Architecture ABI [ 14 ]では、次のようになります。

  • レジスタ0と1は揮発性です
  • レジスタ2と3はパラメータの受け渡しと戻り値のために使用されます
  • レジスタ4と5はパラメータの受け渡しにも使用される
  • レジスタ6はパラメータの受け渡しに使用され、呼び出し側によって保存および復元される必要がある。
  • レジスタ7から13は呼び出し側が使用するもので、呼び出し側が保存して復元する必要がある。
  • レジスタ14は戻りアドレスとして使用される
  • レジスタ15はスタックポインタとして使用される
  • 浮動小数点レジスタ0と2はパラメータの受け渡しと戻り値のために使用される
  • 浮動小数点レジスタ4と6は呼び出し側が使用するもので、呼び出し側で保存および復元する必要がある。
  • z/Architectureでは、浮動小数点レジスタ1、3、5、および7から15は呼び出し側によって使用されます。
  • アクセスレジスタ0はシステム使用のために予約されています
  • アクセスレジスタ1から15は呼び出し側が使用します

追加の引数はスタックに渡されます。

スーパーH

登録するWindows CE 5.0 [ 15 ]gcc [ 16 ]ルネサス[ 17 ]
R0戻り値。アセンブリ擬似命令を拡張するための一時的な値。8/16ビット演算の暗黙的なソース/デスティネーション。保存されません。戻り値、呼び出し元が保存変動性/一時的。保証はされません
R1..R3一時レジスタとして機能します。保存されません。呼び出し元がスクラッチを保存しました。構造体のアドレス(デフォルトでは呼び出し元が保存)変動性/一時的。保証はされません
R4..R7整数引数の最初の4ワード。引数ビルド領域は、引数を保持するR4からR7までのワードを格納できる領域を提供します。保持されません。パラメータ渡し、呼び出し側が保存引数。保証されません。
R8..R13永久記録として機能します。保存されます。呼び出し先保存変動性/一時的。保証あり。
R14デフォルトのフレーム ポインタ。(R8 ~ R13 もフレーム ポインタとして機能し、リーフ ルーチンはR1 ~ R3 をフレーム ポインタとして使用する場合もあります。) 保持されます。フレーム ポインタ、FP、呼び出し先の保存変動性/一時的。保証あり。
R15スタック ポインターまたは永続レジスタとして機能します。保存されます。スタックポインタ、SP、呼び出し先保存スタックポインタ。保証します。

注意: 「preserved」は呼び出し先の保存を予約します。「guaranted」の場合も同様です。

68k

モトローラ68000シリーズの最も一般的な呼び出し規約は次のとおりです。[ 18 ] [ 19 ] [ 20 ] [ 21 ]

  • d0、d1、a0、a1はスクラッチレジスタです
  • 他のすべてのレジスタは呼び出し先で保存されます
  • a6はフレームポインタであり、コンパイラオプションで無効にすることができます。
  • パラメータは右から左へスタックにプッシュされます
  • 戻り値はd0に格納されます

IBM 1130

IBM 1130は、小型の16ビットワードアドレス指定可能なマシンでした。6つのレジスタと状態インジケータのみを備え、スタックはありませんでした。レジスタは、命令アドレスレジスタ(IAR)アキュムレータ(ACC)アキュムレータ拡張(EXT)、および3つのインデックスレジスタX1~X3です。呼び出し側プログラムは、ACC、EXT、X1、X2を保存する責任があります。[ 22 ]サブルーチンを呼び出すための疑似命令には、CALLメインプログラムに直接リンクされた非再配置可能サブルーチンをコーディングするためのものと、転送ベクターLIBFを介して再配置可能ライブラリサブルーチンを呼び出すためのものの2つがあります。[ 23 ]どちらの疑似命令も、次の命令のアドレスを実効アドレス(EA)に格納し、EA+1に分岐するBranch and Store IAR()マシン命令 に解決されます。BSI

引数はBSI‍(通常は引数の1ワードアドレス)に続きます。呼び出されるルーチンは、戻り時に引数をスキップできるように、引数の数を把握しておく必要があります。引数はレジスタで渡すこともできます。関数ルーチンは、実引数の場合はACCに、実数擬似アキュムレータ(FAC)と呼ばれるメモリ位置に結果を返しました。引数と戻りアドレスは、サブルーチンの最初の位置に格納されているIAR値へのオフセットを使用してアドレス指定されました。

 * 1130 サブルーチンの例 ENT SUB "SUB"を外部エントリポイントとして宣言する SUB DC 0 エントリポイントの予約語。通常は「DC *-*」と表記されます。 * サブルーチンコードはここから始まり * 引数がある場合、アドレスは戻りアドレスから間接的にロードできます LDX I 1 SUB X1に最初の引数のアドレスをロードする(例) ... * 戻りシーケンス LD RES 整数結果をACCにロードする * 引数が指定されていない場合は、保存された戻りアドレスへの間接分岐 BI SUB 引数が指定されていない場合 END SUB 

IBM 1130、CDC 6600PDP-8(これら3つのコンピュータはすべて1965年に導入された)のサブルーチンは、戻りアドレスをサブルーチンの最初の位置に格納する。[ 24 ]

マシンアーキテクチャ外の呼び出し規約

スレッドコード

スレッド化されたコードでは、関数呼び出しの準備と後処理の責任はすべて呼び出される側のコードに委ねられます。呼び出し側のコードは、呼び出されるサブルーチンをリストアップするだけです。これにより、関数の準備と後処理のコードは、関数が呼び出される複数の場所ではなく、関数のプロローグとエピローグという1か所にまとめられます。そのため、スレッド化されたコードは最もコンパクトな呼び出し規約となります。

スレッドコードはすべての引数をスタックに渡します。すべての戻り値もスタックに返されます。そのため、単純な実装は、より多くの値をレジスタに保持する呼び出し規約よりも遅くなります。しかし、スタックの上位値(特に戻りアドレス)のいくつかをレジスタにキャッシュするスレッドコード実装は、戻りアドレスを常にスタックにプッシュおよびポップするサブルーチン呼び出し規約よりも通常は高速です。[ 25 ] [ 26 ] [ 27 ]

PL/I

PL/I言語で書かれたプログラムのデフォルトの呼び出し規約では、すべての引数は参照渡しされるが、オプションで他の規約を指定することもできる。[ 28 ]引数の扱い方はコンパイラやプラットフォームによって異なるが、通常、引数のアドレスはメモリ内の引数リストを介して渡される。戻り値を格納する領域を指し示す最終的な隠しアドレスを渡すこともできる。PL/Iがサポートするデータ型は多種多様であるため、例えば文字列やビット文字列の長さ、配列(ドープベクトル)の次元と境界、データ構造のレイアウトと内容を定義するデータ記述子も渡すことができる。定数である引数や、呼び出された手続きが期待する引数の型と一致しない引数については、ダミー引数が作成される。 [ 29 ]

参照

説明ノート

  1. ^アクセス レジスタ (AR) モードまたは 64 ビット アドレス モードの呼び出し元が許可されている場合は、他のサイズもあります。

参考文献

  1. ^ a b「呼び出し規約」 . cs.cornell.edu . 2024年3月5日閲覧。
  2. ^ "/Oy (フレームポインター省略)" . learn.microsoft.com . 2021年8月3日. 2024年6月14日閲覧
  3. ^ 「ARMアーキテクチャのプロシージャ呼び出し標準」。2021年。
  4. ^ 「汎用レジスタのパラメータ」 ARM Cortex-Aシリーズ ARMv8-A向けプログラマーズガイド2020年11月12日閲覧
  5. ^ 「NEONおよび浮動小数点レジスタのパラメータ」 developer.arm.com 2020年11月13日閲覧
  6. ^ 「RISC-V呼び出し規約」(PDF)
  7. ^ 「MIPS32 命令セットクイックリファレンス」
  8. ^スウィートマン、ドミニク. MIPS Run(第2版)参照. Morgan Kaufmann Publishers . ISBN 0-12088-421-6
  9. ^ a b「MIPS ABI History」2018年8月26日時点のオリジナルよりアーカイブ2020年8月17日閲覧。
  10. ^ Christopher, Eric (2003年6月11日). 「mips eabi ドキュメント」 . [email protected] (メーリングリスト) . 2020年6月19日閲覧
  11. ^ “NUBI” . 2021年7月29日時点のオリジナルよりアーカイブ2020年8月16日閲覧。
  12. ^ System V アプリケーションバイナリインタフェース SPARC プロセッサ補足(第 3 版)。
  13. ^ 「S/390 ELF アプリケーションバイナリインターフェースサプリメント」
  14. ^ 「zSeries ELF アプリケーション バイナリ インターフェース サプリメント」
  15. ^ 「Renesas SH-4レジスタ」 . Microsoft Learn . 2007年7月9日.
  16. ^ 「SH Application Binary Interface for GCC」 。2014年11月5日時点のオリジナルよりアーカイブ
  17. ^ 「SuperH RISC engine C/C++コンパイラ、アセンブラ、最適化リンケージエディタ、コンパイラパッケージ V.9.00 ユーザーズマニュアル」(PDF) 。2016年3月15日時点のオリジナル(PDF)からアーカイブ
  18. ^スミス、マイク博士。「SHARC(21k)と68kレジスタの比較」
  19. ^ XGCC: 組み込み開発向けGNU C/C++言語システム(PDF) . Embedded Support Tools Corporation. 2000年. p. 59.
  20. ^ 「COLDFIRE/68K: ThreadX for the Freescale ColdFire Family」 。2015年10月2日時点のオリジナルよりアーカイブ
  21. ^ Moshovos, Andreas. 「サブルーチンの続き:引数の受け渡し、値の戻り値、ローカル変数の割り当て」。d0 、d1、a0、a1、a7を除くすべてのレジスタは、呼び出し全体で保持される必要があります。
  22. ^ IBM Corporation (1967). IBM 1130 ディスクモニターシステム バージョン2 システム概要 (C26-3709-0) (PDF) p. 67 . 2014年12月21日閲覧
  23. ^ IBM Corporation (1968). IBM 1130 アセンブラ言語 (C26-5927-4) (PDF) . pp.  24– 25.
  24. ^ Smotherman, Mark (2004). 「サブルーチンおよびプロシージャ呼び出しのサポート:初期の歴史」 .
  25. ^ロドリゲス、ブラッド。「Moving Forth、パート1:Forthカーネルにおける設計上の決定」。6809またはZilog Super8では、DTCはSTCよりも高速です。
  26. ^エルトル、アントン。「さまざまな通訳派遣技術の速度」
  27. ^ Zaleski, Mathew (2008). 「第4章 効率的なインタープリテーションの設計と実装」 . YETI: 段階的に拡張可能なトレースインタープリタ.直接スレッド化されたインタープリタは分岐予測特性が低いことが知られていますが…呼び出しと戻りのレイテンシは間接ジャンプよりも大きくなる可能性があります。
  28. ^ 「IBMの360および初期の370システム」
  29. ^ 「IBMの360および初期の370システム」