エイリアス パラメーターは、指定された特定のシンボル用にカスタム作成された新しいコードを生成します。これには、コンテキスト内のものが含まれます。
分解を見てみましょう:
0805c850 <_D6test564mainFZv20__T12__dgliteral1TiZ12__dgliteral1MFNbNfiZb>:
805c850: 55 push ebp
805c851: 8b ec mov ebp,esp
805c853: 83 ec 04 sub esp,0x4
805c856: 8b 48 d8 mov ecx,DWORD PTR [eax-0x28]
805c859: 3b 4d 08 cmp ecx,DWORD PTR [ebp+0x8]
805c85c: 0f 9f c0 setg al
805c85f: 0f b6 c0 movzx eax,al
805c862: c9 leave
805c863: c2 04 00 ret 0x4
これは、ここで作成されたリテラル デリゲートです (最適化なし)。興味深い行は、中央の mov と cmp です。
コンテキスト ポインターは、eax レジスターでデリゲートに渡されることに注意してください。これがどこで呼び出されるか見てみましょう:
0805c868 <_D6test5632__T4findS18main12__dgliteral1TiZ4findMFNaNbNfAiZAi>:
// snip a bunch of irrelevant code
805c870: 89 45 fc mov DWORD PTR [ebp-0x4],eax
// snip
805c892: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
805c895: 89 95 f8 ff ff ff mov DWORD PTR [ebp-0x8],edx
805c89b: e8 b0 ff ff ff call 805c850 <_D6test564mainFZv20__T12__dgliteral1TiZ12__dgliteral1MFNbNfiZb>
そこにある 2 つの点に注意してください。まず、名前: dgliteral がそこにあることに注意してください。これは、この特定の引数に対して特別に生成された関数です!
次に、eax でこの関数に渡されたものはすべて格納され、最終的に他の関数にも渡されることに注意してください。
もう一度コール スタックを上ってみましょう。今、find コールが表示される _Dmain にいます。
805c7da: 89 e8 mov eax,ebp
805c7dc: e8 87 00 00 00 call 805c868 <_D6test5632__T4findS18main12__dgliteral1TiZ4findMFNaNbNfAiZAi>
ベースポインタを渡しています!ところで、0x28 を覚えていますか? _Dmain でも確認できます。いくつかの行があります。
805c7d1: c7 45 d8 fe ff ff ff mov DWORD PTR [ebp-0x28],0xfffffffe
それがint z = -2;
行です (-2 は 32 ビットでは fffffffe として表されます)。通常のローカル変数のようにスタックに格納されます。
要するに、特定のエイリアス引数が、すべてのローカル変数がどこにあるかを知っているまったく新しい関数を生成するということです。呼び出されると、それらへの基本ポインタが転送されます。これだけで十分です。
ところで、ローカル変数をエイリアス params として渡して同様のコードを取得することもできることに注意してください。これは、ポインターを取得するのではなく、オフセットを直接突く関数を作成します。
また、ランタイム デリゲートをエイリアス引数に渡そうとしたり、エイリアス dg を別の場所に保存しようとすると、コンパイルされません。これはケース固有のコードを持つ特別な関数であり、一般的なデリゲートの多くはうまく機能しません。