fastcall
多くの関数の前に表記が追加されているのを見てきました。なぜ使われるのですか?
2 に答える
関数の前のその表記は「呼び出し規約」と呼ばれます。これは、(低レベルで)コンパイラーが入力パラメーターを関数に渡し、実行後にその結果を取得する方法を指定します。
多くの異なる呼び出し規約がありますが、最も人気のあるものはstdcall
とcdecl
です。
それを行う方法は1つしかないと思うかもしれませんが、実際には、関数を呼び出して変数を出し入れする方法は数十あります。入力パラメーターをスタックに配置できます(プッシュ、プッシュ、プッシュして呼び出し、ポップ、ポップ、ポップして入力パラメーターを読み取ります)。あるいは、レジスターにそれらを貼り付けたいと思うかもしれません(これはfastcall
、速度のためにいくつかの入力パラメーターをレジスターに適合させようとします)。
しかし、注文はどうですか?それらを左から右に押しますか、それとも右から左に押しますか?結果はどうですか?(参照パラメーターがないと仮定すると)常に1つしかないので、結果をスタックのレジスターの特定のメモリアドレスに配置しますか?
また、通信にスタックを使用していると仮定しましょう-関数が呼び出された後に実際にスタックをクリアするのは誰の仕事ですか-呼び出し元または呼び出し先ですか?
(特定の)CPUレジスタの内容をバックアップしてから復元するのはどうですか?呼び出し元はそれを行う必要がありますか、それとも呼び出し先はすべてを元の状態に戻すことを保証しますか?
最も人気のある呼び出し規約(これまでのところ)はcdecl
、CとC++の両方の標準の呼び出し規約です。WIN32 APIはを使用しますstdcall
。これは、WIN32 APIを呼び出すすべてのコードが、stdcall
それらの関数呼び出しに使用する必要があることを意味します(これは別の一般的な選択肢になります)。
fastcall
少し奇妙なことです-人々は1つの入力/出力パラメータだけで多くの関数を実現しました、メモリベースのスタックからのプッシュとポップはかなりのオーバーヘッドであり、関数呼び出しを少し重くするので、異なるコンパイラが導入されました(異なる)パフォーマンスを向上させるために、残りをスタックに配置する前に1つ以上のパラメーターをレジスターに配置する呼び出し規約。問題は、すべてのコンパイラが、何がどこに行き、誰が何をするかについて同じルールを使用しているfastcall
わけではないことです。その結果、誰が何をするかわからないため、使用するときは注意が必要です。最後に、fastcallは本当に速いですか?を参照してください。fastcall
パフォーマンス上の利点に関する情報。
複雑なもの。
覚えておくべき重要なこと:自分が何をしているのか正確にわからない場合は、呼び出し規約を追加または変更しないでください。発信者と着信者の両方が呼び出し規約に同意しないと、最終的にはスタックの破損とセグメンテーション違反が発生します。これは通常、DLL /共有ライブラリで呼び出されている関数があり、DLL / SO / dylibが特定の呼び出し規約(たとえばcdecl
)であることに依存するプログラムが作成されている場合に発生します。その後、ライブラリは別の呼び出し規約で再コンパイルされます。 (たとえば、fastcall
)。これで、古いプログラムは新しいライブラリと通信できなくなります。
fastcallというタイトルの規則は標準化されておらず、コンパイラベンダーに応じて異なる方法で実装されています。通常、fastcall呼び出し規約は、レジスタで1つ以上の引数を渡します。これにより、呼び出しに必要なメモリアクセスの数が減ります。