1

.NET (C# および VB) をフルタイムで 3 年間使用した経験があります。MSIL について十分な知識があり、デバッグ ツールとして使用できます。

コンパイル プロセスの次のステップ、つまり、Jitter がいつアセンブリ コードを生成するか (dissassebly ウィンドウに表示される) について、私はあまり知りません。Hans Passant が質問への回答を投稿しました:ネイティブ コード、マシン コード、アセンブリ コードの違いは何ですか? . 私のより経験豊富な同僚は、これは素晴らしい答えだと言いましたが、私はまだ次のコードを理解していません:

static void Main(string[] args) {
            Console.WriteLine("Hello world");
00000000 55                push        ebp                           ; save stack frame pointer
00000001 8B EC             mov         ebp,esp                       ; setup current frame
00000003 E8 30 BE 03 6F    call        6F03BE38                      ; Console.Out property getter
00000008 8B C8             mov         ecx,eax                       ; setup "this"
0000000a 8B 15 88 20 BD 02 mov         edx,dword ptr ds:[02BD2088h]  ; arg = "Hello world"
00000010 8B 01             mov         eax,dword ptr [ecx]           ; TextWriter reference
00000012 FF 90 D8 00 00 00 call        dword ptr [eax+000000D8h]     ; TextWriter.WriteLine()
00000018 5D                pop         ebp                           ; restore stack frame pointer
        }
00000019 C3                ret                                       ; done, return

各行で何が起こっているのか、特に各レジスタが選択された理由、たとえば edx ではなく eax が選択された理由について、より多くの情報を提供できる人はいますか? あるいは、誰かが本を推薦できますか?

4

2 に答える 2

3

私はこれに少し慣れていませんが、低レベルのアセンブリの側面にも興味があります。ここに行きます:

push ebp; save stack frame pointer

EBP に格納された値をスタックにプッシュして、このメソッドから戻ったときにどこから来たかを認識できるようにします。

mov ebp,esp; setup current frame

EBP が現在のメソッドのコンテキスト内にあるように、現在のスタック位置の値を ESP から EBP に移動します。

前の 2 行のコードは、ローカル変数の相対位置を決定するスタック上の固定位置 (EBP レジスタに格納される) を確保する規則です。

call 6F03BE38; Console.Out property getter

これがConsole.Outの呼び出しであると推測しても賞品はありません

mov ecx,eax; setup "this"

メソッドからの戻り値は EAX に格納されますが、これは呼び出し規約の問題です。したがって、からの戻り値Console.Outは EAX に格納されます。ここで、その値は後で使用するために ECX にコピーされ、EAX は他の目的に使用できるようになります。

mov edx,dword ptr ds:[02BD2088h]; arg = "Hello world"

レジスタ EDX には、文字列 "Hello World" のメモリ位置が与えられます。dword ptr ds:[02BD2088h]はメモリ位置を逆参照することを意味しますds:[02BD2088h]。ここdsで、 はデータ セグメントです(初期化された文字列などが格納される場所)。[02BD2088h]のメモリ領域のオフセットですds

mov eax,dword ptr [ecx]; TextWriter reference

その電話を覚えていConsole.Outますか?そこから返された値を ECX に入れます。ここでは、ECX のメモリ アドレスが逆参照されているため、TextWriter のメモリ アドレスが EAX にコピーされます。したがって、EAX には TextWriter オブジェクトの実際のメモリ アドレスが含まれます。その場合mov eax,dword ptr ecx;、EAX には、TextWriter の実際のメモリ アドレスではなく、TextWriter のメモリ アドレスへのポインタが含まれます。(私はまだそれについて混乱しています)。

call dword ptr [eax+000000D8h]; TextWriter.WriteLine()

ここで に電話をかけTextWriter.WriteLine()ます。私はそれが呼び出し規約TextWriter.WriteLine()を使用していると仮定しています_fastcall(呼び出し規約の良い説明はここにあります)。つまり、EDX レジスタを使用してメソッドに渡された引数を見つけます。

pop ebp; restore stack frame pointer

最上位 (実際にはスタックが下に向かって成長するため、実際には最下位) の値を EBP に削除するため、EBP のフレーム ポインターは呼び出し元のメソッドに対応するようになります。

ret

スタックの一番上にある場所に戻り、呼び出し元のメソッドに戻ります。この場合、Main()呼び出されると、制御がシステム コードに返され、アプリケーションが終了します。

于 2013-08-28T21:04:15.587 に答える
1

最初の 2 行は、スタック フレームの設定に使用されます。このEBPレジスタは、現在のメソッドのフレームのベース アドレスを格納するために使用されます。

push        ebp

呼び出し元メソッドのフレームのベース アドレスをスタックに保存します。これは、関数が終了する直前に復元されます

pop         ebp

最後の命令の前のret命令。

コメントが示唆するように、

call        6F03BE38

命令はConsole.Outプロパティ ゲッターを呼び出します。これは静的メソッドであるため、メソッドのアドレスは、現在のメソッドがコンパイルされたときに JIT によって直接挿入された可能性があります。

Windows 上の関数は通常、_stdcall呼び出し規約を使用します。呼び出し規則は、引数を関数に渡す方法 (スタック経由またはレジスタ経由)、スタックに渡す順序 (左から右または右から左)、およびクリーニングの責任者を指定します。呼び出し後のスタック (呼び出し元または呼び出し先)。引数がないため、getter の規則が明確ではありませんが、戻り値は EAX レジスタに配置されているようです。

次の 3 行は、への呼び出しをセットアップします。TextWriter.WriteLine

この線:

mov         ecx,eax

EAX の値を ECX に移動します。EAX には、Console.Outゲッターから返された値が含まれます。

この線

mov         edx,dword ptr ds:[02BD2088h]

文字列 "Hello world" のアドレスを EDX レジスタに移動します。

この線

mov         eax,dword ptr [ecx]

が指すアドレスの単語をECXEAX にコピーします。EAX には から返された値が含まれますConsole.Out。これは参照型であるため、この値はヒープに格納されているオブジェクトへのポインターです。すべてのオブジェクトには、同期ブロック インデックスとメソッド テーブルへのポインタで構成されるオブジェクト ヘッダーがあります。参照自体は、メソッド テーブルを直接指しています。したがって、[ECX] は、TextWriterメソッドが呼び出される参照のメソッド テーブル ポインターのアドレスです。

最後に、メソッドが呼び出されます

call        dword ptr [eax+000000D8h]

000000D8h、メソッドに対応するメソッド テーブルへのオフセットTextWriter.WriteLineです。

thisポインターとstring引数は ECX と EDX に格納されるため、このメソッドは _fastcall 規則を使用しているように見えます

于 2013-08-28T21:12:36.670 に答える