マイクロソフトの中間言語MSILを解読する中間言語の概要

6343 ワード

.Netフレームワークでは、共通言語インフラストラクチャは、共通言語仕様を使用して異なる言語をバインドします.異なる言語に対して少なくとも共通タイプシステム(CTS)が共通言語仕様に含まれる部分を実現することを要求することによって、共通言語インフラストラクチャは異なる言語で.Netフレームワークを使用することを許可する.そのため.Netフレームワークでは、すべての言語(C#,VB.Net,Effil.Netなど)は最後に共通言語:マイクロソフト中間言語(MSIL)に変換される.
MSILは.Netコードをマシン言語に変換する中間プロセスである.高度な言語とIntelベースのアセンブリ言語に介在する擬似アセンブリ言語である.ユーザが.Netプログラムをコンパイルすると、コンパイラはソースコードを効率的にネイティブコードに変換できるCPUとは独立した命令のセットに翻訳する.これらの命令を実行すると、リアルタイム(JIT)コンパイラはこれらをCPU固有のコードに変換します.共通言語実行ライブラリは複数のリアルタイムコンパイラをサポートしているため、同じセグメントのMSILコードを異なるコンパイラによってリアルタイムでコンパイルして異なる構造上で実行することができます.理論的には、MSILは長年にわたって業界内の異なる言語間の紛争を解消します..Netの世界では、次のような状況が発生する可能性があります.コードはEffilで実現でき、もう一部のコードはC#やVBで完成するが、最後にこれらのコードは中間言語に変換される.これはプログラマーに大きな柔軟性を提供し、プログラマーは自分のよく知っている言語を選択することができ、絶えず押し出された新しい言語を学ぶために悩む必要はない.
マイクロソフトの中間言語を解読する一連の文章は、簡単で分かりやすい方法で中間言語の複雑な原理を明らかにする.これらの原理は詳細な例で述べる.いくつかの例ではソースコードと中間コードを同時に与え、ソースコードと中間コードを比較することで、コンパイラの限界をよりよく理解し、より速い世代を書くように指導する.コード.
マイクロソフト中間言語の概要
1.中間言語で作成された簡単なプログラム
古典的なHello Worldの例から始めましょう.まず、テキストエディタに次のコードを入力し、Hello World.ilとして保存します.

      
       .assembly HelloWorldIL {}
       
.method static void HelloWorld()
{
.entrypoint
ldstr "Hello World."
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}

中間言語プログラムで、行が「.」で始まると、関数やクラスを生成するなど、アセンブリツールにいくつかの操作を実行するように要求されるアセンブリツールに送信される命令を表します.最初の行は中間言語のコードです.中間言語ではメソッドはアセンブリコマンドmethodで定義され、アセンブリコマンドの後にメソッドの戻り値、名前、パラメータが続きます.メソッド体は{}に含まれます.例のretはメソッドの終わりを表します.
中間言語ファイルには多くの関数が含まれていてもよく、アセンブリツールではまずどの方法を実行すべきかを見分けることができません.C#やVBのような高度な言語では、プログラムのエントリ方法には通常、C#のpublic static void Main()などの特定の名前があります.を選択します.これが、上記のアセンブリツールがエラーメッセージを発行した理由です.中間言語では、最初に実行されるメソッドをエントリ関数(EntryPoint Function)と呼びます..アセンブリツールHelloWorldがエントリ関数であることを示すには、メソッドボディの任意の場所に配置できるアセンブリコマンドentrypointをコードに追加する必要があります.1つのプログラムセットにエントリ関数が1つしかないことに注意してください.
中間言語コードは、通常、プログラムセットに属するモジュールにコンパイルされます..Netでは、モジュールとプログラムセットの概念が非常に重要であるため、開発者はそれらを明確に理解する必要があります.後述する.Netプログラムの構造について詳しく説明します.コードにassemblyコマンドを追加することで、アセンブリツールの中間コードがそのモジュールに属していることを伝えることができます.プログラムセット.assemblyコマンドのフォーマットは次のとおりです.

      
       .assembly <     > {}
      

methodコマンドの後にstaticキーワードが追加されていることに注意してください.これは、各エントリ関数が静的でなければならないためです.たとえば、C#では、Mainメソッドをpublic static void Main()として定義します.
次に、WriteLineメソッドを呼び出してHelloWorld文字列を画面に出力する必要があります.callコマンド(Instruction)を使用することで、この目的を達成できます.コマンドのフォーマットは次のとおりです.

      
       call <return type> <namespace>.<class name>::<method name>
      

ここで、メソッドを呼び出す場合、中間言語と他のプログラミング言語には大きな違いが見られます.中間言語では、メソッドを呼び出す必要がある場合、メソッドの名前ドメイン(namespace)、クラス名、戻り値タイプ、パラメータのデータ型を含むメソッドのフルネームを指定する必要があります.これにより、アセンブリツールが正しいメソッドを見つけることができることを保証します.
WriteLineメソッドを呼び出すには文字列パラメータが必要です.メソッドまたは関数に渡されるすべてのパラメータはメモリのスタックに保存されます.中間言語には、スタックから文字列をロードする命令ldstrがあります.(スタックはメモリの領域で、パラメータをメソッドに転送するために使用されます.後でスタックの問題を詳しく説明します).すべてのメソッドはスタックからパラメータを取得するため、ldstrコマンドは不可欠です.ldstrコマンドのフォーマットは次のとおりです.

      
       ldstr <parameter string>
      

ILAsm.exeでこのプログラムをコンパイルできます.ILAsm.exeを実行する前に、まずWindowsオペレーティングシステムのPath環境変数に含まれていることを確認する必要があります.ILAsm.exeは次のパスで見つけることができます.

      
       %windir%/Microsoft.NET/Framework/v1.0.xxxx
      

ここで、xxxxxは使用中の.NETフレームワークの内部バージョン番号です.たとえば、私が使用しているバージョン番号が3705の場合、Path環境変数は次のように設定します.

      
       Set Path = %Path%;c:/Windows/Microsoft.NET/Framework/v1.0.3705
      

次にcmd.exeを実行します(開始->実行->入力cmd->確認キーを押します).ポップアップコマンドウィンドウに次のように入力します.

      
       J:/Testcode>ilasm HelloWorld.il
      

コードをまとめてプログラムを実行するとHello World.の出力が表示されます.
上記の例を通して、中間言語のプログラム構造、いくつかのコマンドと命令を理解しました.同時に、中間言語が大文字と小文字を区別していることを注意する必要があります.
2.改善されたHelloWorldの例
.Netのすべての言語はオブジェクト向けの言語ですが、上のHelloWorldの例は構造化された例です.次に、オブジェクト向けのコードに変換する方法を見てみましょう.オブジェクト向けのプログラミングでは、操作をクラスに定義します.上のHelloWorldの例をオブジェクト向けのコードに変換するには、classコマンドを使用します.

      
       .class HelloWorld
       
{
}

classコマンドの後に続くのはクラスの名前です.クラスの名前は中間言語でオプションです.また、アクセス制御クラスのメモリ内のレイアウトや相互運用性など、このコマンドに属性を追加する必要があります.コードは次のようになります.

      
       .assembly HelloWorldIL {}
       
.class public auto ansi HelloWorld extends [mscorlib]System.Object
{
.method public hidebysig static void HelloWorld() cil managed
{
.entrypoint
ldstr "Hello World."
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
}

コードには、次の3つの属性が使用されます.
・public:publicは、クラスにアクセスするメンバーに制限がないことを示すアクセス制御属性です.
・auto:autoプロパティは、クラスがメモリにロードされると、メモリ内のレイアウトがプログラムではなく共通実行ライブラリによって決定されることを示します.
・ansi:ansi属性を指定するのは、管理されていないコードと管理されていないコードとの間でシームレスな変換を実現するためです..Netでは、共通言語インフラストラクチャに直接適用できないコードを、C、C++およびVB 6などの管理されていないコードと呼びます.管理されているコードと管理されていないコードとの間の相互運用性を処理するための属性が必要です.管理されているコードでは、文字列は2バイトのUnicode文字で表され、管理されているコードでは、文字列は1バイトのANSI文字で表される可能性があります.ansi属性を指定すると、異なるコード間で文字列を変換できます.
.Netフレームワークでは、すべてのクラスが直接または間接的にSystem.Objectクラスを継承していることを知っています.コードでは、HelloWorldがSystem.Objectを継承していることを明確に指定しています.
HelloWorldメソッドには、public、hidebysig、cil managedプロパティが追加されています.以下に、これらのプロパティの説明を示します.
・public:C#またはVB.Netでメソッドを定義する場合、メソッドのアクセス修飾子を指定する必要があります.アクセス修飾子はpublic、protected、internal、privateです.
・hidebysig:1つのクラスは他のクラスを継承することができ、hidebysig属性は現在のクラスのメソッドが親としてクラスに継承されないことを保証する.例えば、HelloWorldChildクラスがHelloWorldクラスを継承した場合、HelloWorldChildメソッドはHelloWorldメソッドには表示されない.
・cil managed:この属性は後述する.
高度な言語(C#,VB.Netなど)各クラスにはコンストラクション関数が必要であり、コンストラクション関数の最初の行には、ベースクラスのコンストラクション関数を呼び出す必要があります.クラスにコンストラクション関数がない場合、ベースクラスのコンストラクション関数は自動的に呼び出されます.通常、これはコンパイラによって自動的に完了します.次に、.ctorコマンドでベースクラスのコンストラクション関数を呼び出すコンストラクション関数をコードに追加します.
小結
本稿では、古典的なHello Worldの例から、マイクロソフトの中間言語の基本的な文法規則と、中間言語と他の開発言語との関係を実例で理解します.次の文章では、これに基づいて、実例プログラムを用いて.netアプリケーションのフォーマットや構造などを説明します.