Vtable サンクに関するネット上の記事を読んでいましたが、サンクを使用して /chain プロシージャ呼び出しをフックできることをどこかで読みました。
それは達成可能ですか?
それがどのように機能するか知っている人はいますか? また、サンクを説明する適切なリソースを見つけることができません。そのための提案はありますか?
Vテーブルサンクのスタイルで生のサンクを実装することは、最後の手段です。達成する必要のあることはすべて、ラッパー関数を使用して達成できる可能性が高く、苦痛ははるかに少なくなります。
一般に、サンクは次のことを行います。
それがどのように機能するかの例を見るには、私たちの親友であるレイモンド・チェンと彼のアジャスターサンクについての議論に目を向けましょう。
http://blogs.msdn.com/oldnewthing/archive/2004/02/06/68695.aspx
彼が使用したサンクは次のとおりです。
[thunk]:CSample::QueryInterface`adjustor{4}':
sub DWORD PTR [esp+4], 4 ; this -= sizeof(lpVtbl)
jmp CSample::QueryInterface
彼が説明しているように、複数のインターフェースを介して同じメソッドを実装するクラスがあるため、複数のvテーブルがあります。(COMを知らない場合、知っておく必要があるのは、COMがvテーブルで直接機能することだけです。したがって、特定のインターフェイスへのポインターには、そのインターフェイスのすべてのメソッドへの関数ポインターが順番に含まれている必要があります。)
特定のスロットに異なるメソッドで2つのインターフェイスを実装する場合は、複数のvテーブルが必要です。ただし、重複するメソッドは1回しか記述しないため、メソッドは両方の「this」ポインターを処理できる必要があります。これを行うために、コンパイラは必要な修正を実行するメソッドを生成し、元の実装を呼び出します。
したがって、このサンクは次の手順を実行します。
ここでjmp
命令が出てきます。通常、を使用して関数を呼び出すと、関数call
が返さret
れ、呼び出し元に戻る必要があります。実行するクリーンアップがないため、コンパイラーは最適化を実行して、実行を実際の実装に直接移動し、実際の実装のreturnステートメントを呼び出し元に返します。これは単なる最適化であり、サンキングの基本的な部分ではありません。たとえば、16/32ビットサンクは必要に応じて入力/出力パラメータを16ビットと32ビットの間で変換するため、クリーンアップ手順をスキップすることはできません。する必要がありますcall
、ではありませんjmp
。
話の教訓は、jmp
最適化など、C ++やその他の高水準言語で直接記述できないことを行う必要がある場合は、先に進んでアセンブリ言語サンクを記述してください。それ以外の場合は、ラッパーを作成してそれで完了します。
正直なところ、パフォーマンスの最適化を求めているようです。ほとんどの場合、(1)コンパイラは私たちが考えるよりも最適化に優れており、(2)思ったほど大きな改善は得られません。
さて、あなたはサンクが解決策であると読みました、そして今あなたは解決すべき問題を探していますか?
サンクは、一般に、マイナーな(通常はハードコードされた)調整を提供する短い「転送」機能です。
VTableチャンクは、現時点ではウィキペディアで非常によく説明されています。それらは共通のパターンを使用します:実行時に計算/余分な作業を避けるために小さな関数を生成します。
私が見た/サンクを使用した他の場所:
ウィンドウハンドルとウィンドウオブジェクトの関連付け:サブクラス化されるウィンドウごとに、オブジェクト参照を使用してウィンドウプロシージャを呼び出す小さなサンクがオンザフライで生成され、サンクがウィンドウプロシージャとして使用されます。
DLLのロードの遅延:サンクは、関数が最初に呼び出されたときにDLLがロードされることを確認します。
COMインターフェイス呼び出しのトラップ:サンクは診断のための注入ポイントを提供し、実際のメソッドにジャンプします。