117

.NET 言語のコンテキストにおけるマシン コードとネイティブ コードについて混乱しています。

それらの違いは何ですか?彼らは同じですか?

4

4 に答える 4

167

これらの用語は、一貫性を欠いて使用される場合があるため、実際には少し混乱します。

マシンコード:これは最も明確に定義されたものです。これは、プロセッサ (実際の作業を行う物理的な金属片) が理解して直接実行するバイトコード命令を使用するコードです。他のすべてのコードは、マシンで実行する前に、マシン コードに変換または変換する必要があります。

ネイティブ コード:この用語は、マシン コード(上記を参照) を意味する場所で使用されることがあります。ただし、アンマネージ コードを意味するために使用されることもあります(以下を参照)。

アンマネージ コードマネージ コード: アンマネージコードは、C や C++ などのプログラミング言語で記述されたコードを指し、マシン コードに直接コンパイルされます。これは、C#、VB.NET、Java などで記述され、ソフトウェアでプロセッサを「シミュレート」する仮想環境 (.NET や JavaVM など) で実行されるマネージ コードとは対照的です。主な違いは、ガベージ コレクションを採用し、オブジェクトへの参照を不透明に保つことによって、マネージド コードがリソース (主にメモリ割り当て) を "管理" することです。アンマネージ コードメモリの割り当てと割り当て解除を手動で行う必要がある種類のコードで、メモリ リーク (割り当て解除を忘れた場合) やセグメンテーション フォールト (割り当て解除が早すぎる場合) が発生することがあります。アンマネージは、通常、null ポインターの逆参照や配列境界のオーバーフローなどの一般的なエラーの実行時チェックがないことも意味します。

厳密に言えば、ほとんどの動的型付け言語 (Perl、Python、PHP、Ruby など) もマネージ コードです。ただし、一般的にはそのように説明されることはありません。これは、マネージ コードが実際には、非常に大規模で本格的な商用プログラミング環境 (.NET および Java) を表すマーケティング用語のようなものであることを示しています。

アセンブリ コード:この用語は一般に、バイト コードを本当に書きたいときに作成するソース コードの種類を指します。アセンブラは、このソースコードを実際のバイトコードに変換するプログラムです。変換は 1 対 1 であるため、コンパイラではありません。ただし、この用語は、使用されるバイトコードの種類に関してあいまいです。つまり、管理対象または非管理対象である可能性があります。管理されていない場合、結果のバイトコードはmachine codeです。管理されている場合、.NET などの仮想環境によってバックグラウンドで使用されるバイトコードになります。マネージ コード (C#、Java など) は、この特殊なバイト コード言語にコンパイルされます。.NET の場合はCommon Intermediate Language (CIL)と呼ばれ、Java では Java バイトコードと呼ばれます。. 通常、一般的なプログラマーがこのコードにアクセスしたり、この言語で直接記述したりする必要はほとんどありませんが、そうした場合、アセンブラーを使用してコードをバイトコードに変換するため、アセンブリ コードと呼ばれることがよくあります。

于 2010-08-08T12:14:44.220 に答える
46

C# プログラムをデバッグするときに Debug + Windows + Disassembly を使用したときに表示される内容は、これらの用語の適切なガイドです。JIT 最適化を有効にしてリリース構成で C# で記述された「hello world」プログラムをコンパイルしたときの注釈付きバージョンを次に示します。

        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

ウィンドウを右クリックし、「Show Code Bytes」にチェックマークを付けて、同様の表示を取得します。

左側の列はマシン コード アドレスです。その値はデバッガーによって偽造され、コードは実際には別の場所にあります。ただし、JIT コンパイラによって選択された場所によっては、どこにでもある可能性があるため、デバッガーはメソッドの開始時に 0 からアドレスの番号付けを開始します。

2 列目はマシン コードです。CPU が実行する実際の 1 と 0。このようなマシン コードは、一般的に 16 進数で表示されます。例としては、0x8B が MOV 命令を選択することです。追加のバイトは、何を移動する必要があるかを CPU に正確に伝えるために存在します。また、CALL 命令の 2 つのフレーバーにも注意してください。0xE8 は直接呼び出し、0xFF は間接呼び出し命令です。

3 列目はアセンブリ コードです。アセンブリは、マシン コードを簡単に記述できるように設計された単純な言語です。これは、IL にコンパイルされる C# と比較されます。アセンブリ コードを変換するために使用されるコンパイラは、「アセンブラ」と呼ばれます。マシンにはおそらく Microsoft アセンブラーがあり、その実行可能ファイル名は ml.exe、64 ビット バージョンの ml64.exe です。アセンブリ言語には、2 つの一般的なバージョンが使用されています。表示されているのは、Intel と AMD が使用するものです。オープン ソースの世界では、AT&T 表記でのアセンブリが一般的です。言語の構文は、 が書かれた CPU の種類に大きく依存し、PowerPC のアセンブリ言語は大きく異なります。

わかりました、それはあなたの質問の2つの用語に取り組みます. 「ネイティブ コード」はあいまいな用語であり、アンマネージ言語でコードを記述するために使用されることも珍しくありません。おそらく有益なのは、C コンパイラによって生成されるマシン コードの種類を確認することです。これは、C の「hello world」バージョンです。

int _tmain(int argc, _TCHAR* argv[])
{
00401010 55               push        ebp  
00401011 8B EC            mov         ebp,esp 
    printf("Hello world");
00401013 68 6C 6C 45 00   push        offset ___xt_z+128h (456C6Ch) 
00401018 E8 13 00 00 00   call        printf (401030h) 
0040101D 83 C4 04         add         esp,4 
    return 0;
00401020 33 C0            xor         eax,eax 
}
00401022 5D               pop         ebp  
00401023 C3               ret   

主に、C# プログラムによって生成されたマシン コードに非常にているため、注釈を付けませんでした。printf() 関数呼び出しは Console.WriteLine() 呼び出しとはかなり異なりますが、それ以外はほぼ同じです。また、デバッガーが実際のマシン コード アドレスを生成していることと、シンボルについて少し賢くなっていることにも注意してください。アンマネージ コンパイラのようにマシン コードを生成した後にデバッグ情報を生成することの副作用。また、マシン コードを同じように見せるために、いくつかのマシン コード最適化オプションをオフにしたことにも言及しておく必要があります。C/C++ コンパイラは、コードを最適化するためにより多くの時間を利用できるため、結果の解釈が困難になることがよくあります。そして、デバッグが非常に困難です。

ここでの重要な点は、JIT コンパイラーによってマネージ言語から生成されたマシン コードと、ネイティブ コード コンパイラーによって生成されたマシン コードの間にほとんど違いがないということですこれが、C# 言語がネイティブ コード コンパイラと競合できる主な理由です。それらの間の唯一の実質的な違いは、サポート関数呼び出しです。その多くは CLR で実装されています。そして、それはガベージコレクターを中心に一次的に展開します。

于 2010-08-08T13:28:20.083 に答える
6

ネイティブ コードとマシン コードは同じもので、CPU が実行する実際のバイトです。

アセンブリ コードには 2 つの意味があります。1 つは、より人間が読める形式に変換されたマシン コードです (命令のバイトは、「JMP」のような短い単語のようなニーモニックに変換されます (コード内の別の場所に「ジャンプ」します)。もう 1 つは、 DLL または EXE に存在する IL バイトコード (C# や VB などのコンパイラが生成する命令バイトで、最終的にはマシン コードに変換されますが、まだ変換されていません) です。

于 2010-08-08T12:04:06.403 に答える
2

.NET では、アセンブリにMS Intermediate Languageコード (MSIL、場合によっては CIL) が含まれます。
これは、「高レベル」のマシン コードのようなものです。

読み込まれると、MSIL はJIT コンパイラによってネイティブ コード (Intel x86 または x64 マシン コード) にコンパイルされます。

于 2010-08-08T12:02:04.800 に答える