ネイティブコード、マシンコード、アセンブリコードの違いは何ですか?


106

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

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


3
この質問について質問があります。この質問はStackOverflowの要件に該当しますか?そうではありませんが、同時に、この種の質問は非常に役立ちます。このタイプの質問が許可されていないと仮定すると、ここでそうでない場合は、これらのタイプの質問をどこにすべきか
Yousuf Azad

回答:


150

これらの用語は一貫性のない方法で使用されることがあるので、確かに少し混乱しています。

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

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

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

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

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


C ++はマシンコードにコンパイルできますが、オペレーティングシステムで実行されるexeなどの他の形式にコンパイルされることが非常によくあります。
Gordon Gustafson、

ガベージコレクションと、通常はマシンコードにコンパイルされる不透明な参照をサポートする言語があります。Common Lispの最も深刻な実装はそれを行います。あなたが言うことは、マイクロソフトがサポートする言語に当てはまるかもしれませんが、Visual Studioでサポートされているよりも多くのコンパイル済み言語があります。
David Thornley、2010

3
@CrazyJugglerDrummer:C ++コンパイラによって生成されたEXEファイルに含まれるコードは、まだマシンコードです。@David Thornley:私はそれらよりもはるかに多くの言語について言及しましたが、不明瞭な奇妙さをすべて言及することで問題を複雑にしたくありませんでした。
ティムウィ

一部のコンパイラは、多くの場合、実際にC / C ++または他の言語からアセンブリ言語にコンパイルしてからアセンブラを呼び出し、アセンブラはそれをオブジェクトファイルに変換します。オブジェクトファイルはほとんどがマシンコードですが、プロセッサのメモリにアクセスする前に少しタッチする必要があります。リンカはそのすべてをプログラムのマシンコードバージョンにリンクします。C / C ++などのポイントは、多くの場合、ユーザーに見えないマシンコードに直接コンパイルされず、途中で2つまたは3つのステップを実行します。たとえばTCCはこれの例外であり、直接マシンコードに送られます。
old_timer 2010

これはつまらないような感じですが、すべてのアセンブラが1-1をオペコードに変換するわけではありません。実際、多くの最新のアセンブラは、クラスのような抽象化構成をサポートしています。例:BorlandのアセンブラーであるTASM。 en.wikipedia.org/wiki/TASM
プライム

45

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

ウィンドウを右クリックして[コードバイトの表示]を選択すると、同様の表示が得られます。

左側の列はマシンコードアドレスです。その値はデバッガによって偽造され、コードは実際には別の場所に配置されます。しかし、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に実装されています。そして、それはガベージコレクターを中心に展開します。


6

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

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


2

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.