共通中間言語

提供: MonoBook
MSILから転送)
移動: 案内検索

共通中間言語(読み:きょうつうちゅうかんげんご、英語:Common Intermediate Language、略称:CIL)とは、Monoおよび.NET Frameworkで用いられるアセンブリ言語、および共通言語基盤CLI.NET仮想マシン)が理解できる架空の機械語のことである。

.NET Frameworkがベータ版だったころまでは「Microsoft Intermediate Language」(MSIL)として知られており、今なおMSILと呼ぶひとは多い。

コード表現とバイナリイメージ表現[編集]

一般的に「中間言語」と言えばバイナリ形式。 だが「共通中間言語」という言葉自体は、アセンブリ言語テキスト)としての意味も、マシン語バイナリ)としての意味もあり、非常に曖昧な表現となっている。どちらを表しているかは文脈から読み取る必要がある。

紛らわしいのでバイナリ形式のことを「マネージドコード」もしくは「ピュアマネージドコード」と呼ぶひともいる。 人によっては「CILコード」と「CILイメージ」で使い分けている人もいる。 どれが正解かは知らない。

なお、このページでは主にアセンブリ言語としての共通中間言語について記載する。

概要[編集]

CILは、オブジェクト指向アセンブリ言語であり、かつ完全にスタックベースの言語である。

.NET Framework系のプログラミング言語で書かれたソースコードは、各種コンパイラコンパイルされてCILイメージに変換される。

CIL自体は特定のプラットフォームに依存しない(特定CPUに依存しない)命令セットで構成されている。そのため理論上は、直接ネイティブコードに変換することも(Monoでは実験的に可能)、.NET Framework仮想マシンである共通言語基盤CLI)で実行することもできる。

MonoDevelopでは、このアセンブリ言語を使ったプロジェクトを作れる。 誰得。

使用例[編集]

CILコードによる「Hello, worldプログラムの例。

// classとかオブジェクト指向な感じだね
.class private auto ansi beforefieldinit AppMain
    extends [mscorlib]System.Object
{
    // C#みたいな感じでコメントも書けるよ
    .method public static hidebysig
        default void Main(string[] args) cil managed
    {
        // どうみてもエントリポイント
        .entrypoint
        .maxstack 8
        ldstr "hello, world"
        call void class [mscorlib]System.Console::WriteLine(string)
        ret
    }
}

CILの命令セット[編集]

コード 命令 概要
0x58 add 2つの値を加算し、新しい値を返す
0xD6 add.ovf 2つの符号付き整数値を加算し、かつオーバーフローのチェックを行い、新しい値を返す。
0xD7 add.ovf.un 2つの符号なし整数値を加算し、かつオーバーフローのチェックを行い、新しい値を返す。
0x5F and 2つの値のビットごとのANDを計算し、新しい値を返す。
0xFE 0x00 arglist 現在のメソッドの引数リストのハンドル(アンマネージポインター)を返す。
0x3B <int32> beq target 2つの値が等しいときに、targetへ処理を移す。
0x2E <int8> beq.s target 2つの値が等しいときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x3C <int32> bge target 値1が値2より大きいまたは等しいときに、targetへ処理を移す。
0x2E <int8> bge.s target 値1が値2より大きいまたは等しいときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x41 <int32> bge.un target 符号なし整数値または順序なし(浮動小数点)を比較し、値1が値2より大きいまたは等しいときに、targetへ処理を移す。
0x34 <int8> bge.un.s target 符号なし整数値または順序なし(浮動小数点)を比較し、値1が値2より大きいまたは等しいときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x3D <int32> bgt target) 値1が値2より大きいときに、targetへ処理を移す。
0x30 <int8> bgt.s target 値1が値2より大きいときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x42 <int32> bgt.un target 符号なし整数値または順序なし(浮動小数点)を比較し、値1が値2より大きいときに、targetへ処理を移す。
0x35 <int8> bgt.un.s target 符号なし整数値または順序なし(浮動小数点)を比較し、値1が値2より大きいときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x3E <int32> ble target 値1が値2より小さいまたは等しいときに、targetへ処理を移す。
0x31 <int8> ble.s target 値1が値2より小さいまたは等しいときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x43 <int32> ble.un target 符号なし整数値または順序なし(浮動小数点)を比較し、値1が値2より小さいまたは等しいときに、targetへ処理を移す。
0x36 <int8> ble.un.s target 符号なし整数値または順序なし(浮動小数点)を比較し、値1が値2より小さいまたは等しいときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x3F <int32> blt target 値1が値2より小さいときに、targetへ処理を移す。
0x32 <int8> blt.s target 値1が値2より小さいときに、targetへ処理を移す。。飛び先がint8の範囲内のとき用。
0x44 <int32> blt.un target 符号なし整数値または順序なし(浮動小数点)を比較し、値1が値2より小さいときに、targetへ処理を移す。
0x37 <int8> blt.un.s target 符号なし整数値または順序なし(浮動小数点)を比較し、値1が値2より小さいときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x40 <int32> bne.un target 符号なし整数値または順序なし(浮動小数点)を比較し、値1と値2が等しくないときに、targetへ処理を移す。
0x33 <int8> bne.un.s target 符号なし整数値または順序なし(浮動小数点)を比較し、値1と値2が等しくないときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x8C <T> box <valTypeToken> 値型をオブジェクト参照に変換する。
0x38 <int32> br target 無条件で、targetへ処理を移す。
0x2B <int8> br.s target 無条件で、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x01 break ブレイクポイントに達したことをデバッガーに通知する。
0x39 <int32> brfalse target 値がfalseまたはnullまたはゼロのときに、targetへ処理を移す。
0x2C <int8> brfalse.s target 値がfalseまたはnullまたはゼロのときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x3A <int32> brinst target 値がnullでもゼロでもないときに、targetへ処理を移す。(brtrueの別名)
0x2D <int8> brinst.s target 値がnullでもゼロでもないときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。(brtrue.sの別名)
0x39 <int32> brnull target 値がnullのときに、targetへ処理を移す。
0x2C <int8> brnull.s target 値がnullのときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x3A <int32> brtrue target 値がnullでもゼロでもないときに、targetへ処理を移す。
0x2D <int8> brtrue.s target 値がnullでもゼロでもないときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。
0x39 <int32> brzero target 値がfalseまたはnullまたはゼロのときに、targetへ処理を移す。(brfalseの別名)
0x2C <int8> brzero.s target 値がfalseまたはnullまたはゼロのときに、targetへ処理を移す。飛び先がint8の範囲内のとき用。(brfalse.sの別名)
0x28 <T> call methodDesc methodDescに書かれたメソッドを呼び出す。
0x29 <T> calli callSiteDescr callSiteDescrで引数の型を指定し、事前にftnで指定したメソッド(評価スタックに積まれてる関数ポインタ)を呼び出す。
0x6F <T> callvirt method オブジェクトの遅延評価メソッドを呼び出し、戻り値を評価スタックに積む。
0x74 <T> castclass class
0xFE 0x01 ceq
0xFE 0x02 cgt
0xFE 0x03 cgt.un
0xC3 ckfinite
0xFE 0x04 clt
0xFE 0x05 clt.un
0xFE 0x16 <T> constrained. thisType
0xD3 conv.i
0x67 conv.i1
0x68 conv.i2
0x69 conv.i4
0x6A conv.i8
0xD4 conv.ovf.i
0x8A conv.ovf.i.un
0xB3 conv.ovf.i1
0x82 conv.ovf.i1.un
0xB5 conv.ovf.i2
0x83 conv.ovf.i2.un
0xB7 conv.ovf.i4
0x84 conv.ovf.i4.un
0xB9 conv.ovf.i8
0x85 conv.ovf.i8.un
0xD5 conv.ovf.u
0x8B conv.ovf.u.un
0xB4 conv.ovf.u1
0x86 conv.ovf.u1.un
0xB6 conv.ovf.u2
0x87 conv.ovf.u2.un
0xB8 conv.ovf.u4
0x88 conv.ovf.u4.un
0xBA conv.ovf.u8
0x89 conv.ovf.u8.un
0x76 conv.r.un
0x6B conv.r4
0x6C conv.r8
0xE0 conv.u
0xD2 conv.u1
0xD1 conv.u2
0x6D conv.u4
0x6E conv.u8
0xFE 0x17 cpblk
0x70 <T> cpobj classTok
0x5B div
0x5C div.un
0x25 dup
0xDC endfault
0xFE 0X11 endfilter
0xDC endfinally
0x4C idind.u8
0xFE 0x18 initblk
0xFE 0x15 <T> initobj typeTok
0x75 <T> isinst class
0x27 <T> jmp method
0xFE 0x09 <uint16> ldarg index
0x02 ldarg.0
0x03 ldarg.1
0x04 ldarg.2
0x05 ldarg.3
0x0E <uint8> ldarg.s index
0xFE 0x0A <uint16> ldarga index
0x0F <uint8> ldarga.s index
0x20 <int32> ldc.i4 num numをInt32型の値とみなしスタックに積む。
0x16 ldc.i4.0 数字の「0」をInt32型の値としてスタックに積む。
0x17 ldc.i4.1 数字の「1」をInt32型の値としてスタックに積む。
0x18 ldc.i4.2 数字の「2」をInt32型の値としてスタックに積む。
0x19 ldc.i4.3 数字の「3」をInt32型の値としてスタックに積む。
0x1A ldc.i4.4 数字の「4」をInt32型の値としてスタックに積む。
0x1B ldc.i4.5 数字の「5」をInt32型の値としてスタックに積む。
0x1C ldc.i4.6 数字の「6」をInt32型の値としてスタックに積む。
0x1D ldc.i4.7 数字の「7」をInt32型の値としてスタックに積む。
0x1E ldc.i4.8 数字の「8」をInt32型の値としてスタックに積む。
0x15 ldc.i4.m1 数字の「-1」をInt32型の値としてスタックに積む。
0x1F <int8> ldc.i4.s num numをInt32型の値とみなしスタックに積む。numがint8の範囲内のとき用。
0x21 <int64> ldc.i8 num numをInt64型の値とみなしスタックに積む。
0x22 <float32> ldc.r4 num numをfloat32型の値とみなしスタックに積む。
0x23 <float64> ldc.r8 num numをfloat64型の値とみなしスタックに積む。
0xA3 <T> ldelem <typeTok>
0x97 ldelem.i
0x90 ldelem.i1
0x92 ldelem.i2
0x94 ldelem.i4
0x96 ldelem.i8
0x98 ldelem.r4
0x99 ldelem.r8
0x9A ldelem.ref
0x91 ldelem.u1
0x93 ldelem.u2
0x95 ldelem.u4
0x96 ldelem.u8
0x8F <T> ldelema class
0x7B <T> ldfld field
0x7C <T> ldflda field
0xFE 0x06 <T> ldftn method
0x4D ldind.i
0x46 ldind.i1
0x48 ldind.i2
0x4A ldind.i4
0x4C ldind.i8
0x4E ldind.r4
0x4F ldind.r8
0x50 ldind.ref
0x47 ldind.u1
0x49 ldind.u2
0x4B ldind.u4
0x8E ldlen
0xFE 0x0C <uint16> ldloc index
0x06 ldloc.0
0x07 ldloc.1
0x08 ldloc.2
0x09 ldloc.3
0x11 <uint8> ldloc.s indx
0xFE 0x0D <uint16> ldloca index
0x12 <uint8> ldloca.s index
0x14 ldnull
0x71 <T> ldobj typeTok
0x7E <T> ldsfld field
0x7F <T> ldsflda field
0x72 <T> ldstr mdToken
0xD0 <T> ldtoken token
0xFE 0x07 <T> ldvirtftn method
0xDD <int32> leave target
0xDE <int8> leave.s target
0xFE 0x0F localloc
0xC6 <T> mkrefany class
0x5A mul
0xD8 mul.ovf
0xD9 mul.ovf.un
0x65 neg 評価スタックの一番上の値を取り出し、「2の補数」を計算し、評価スタックに積む。
0x8D <T> newarr etype etypeで示される配列を作成し、その参照評価スタックに積む。
0x73 <T> newobj ctor 新しいオブジェクトまたは値型の新しいインスタンスを作成し、その参照評価スタックに積む。。
0xFE 0x19 no. { typecheck, rangecheck, nullcheck]] } [prefix]
0x00 nop 何もしない。エディットコンテニューブレイクポイントを使ったときの穴埋め用。
0x66 not 評価スタックの一番上にある値を取り出し、ビットごとの補数1の補数)を計算し、評価スタックに積む。
0x60 or 評価スタックの一番上にある2つの値を取り出し、ビットごとの補数を計算し、評価スタックに積む。
0x26 pop スタックの一番上にある値を取り出す。
0xFE 0x1E readonly. 以降の配列アドレス演算で、実行時に型チェックを実行しないこと、および可変性が制限されたマネージドポインターを返すことを指定する。
0xFE 0x1D refanytype
0xC2 <T> refanyval type
0x5D rem
0x5E rem.un
0x2A ret
0xFE 0x1A rethrow 現在の例外を再スローする。catch ハンドラー内でのみ使える。
0x62 shl 評価スタックから値とシフトするビット数を取り出し、0を使用して左にビットシフト論理シフト)し、結果を評価スタックに積む。
0x63 shr 評価スタックから値とシフトするビット数を取り出し、0を使用して右にビットシフト論理シフト)し、結果を評価スタックに積む。
0x64 shr.un 評価スタックから符号なし整数値とシフトするビット数を取り出し、0を使用して右にビットシフト論理シフト)し、結果を評価スタックに積む。
0xFE 0x1C <T> sizeof valType valTypeで指定された値型のサイズ(バイト数)を算出し、評価スタックに積む。
0xFE 0x0B <uint16> starg num 評価スタックの一番上にある値を取り出し、numで指定したインデックスの引数スロットに格納する。
0x10 <uint8> starg.s num 評価スタックの一番上にある値を取り出し、numで指定したインデックスの引数スロットに格納する。インデックスが8ビット以内のとき用。
0xA4 <T> stelem typeTok
0x9B stelem.i
0x9C stelem.i1
0x9D stelem.i2
0x9E stelem.i4
0x9F stelem.i8
0xA0 stelem.r4
0xA1 stelem.r8
0xA2 stelem.ref
0x7D <T> stfld field
0xDF stind.i
0x52 stind.i1
0x53 stind.i2
0x54 stind.i4
0x55 stind.i8
0x56 stind.r4
0x57 stind.r8
0x51 stind.ref
0xFE 0x0E <uint16> stloc index スタック上の値をインデックス番号indexのローカル変数に取り出す。
0x0A stloc.0 スタック上の値をインデックス番号0のローカル変数に取り出す。
0x0B stloc.1 スタック上の値をインデックス番号1のローカル変数に取り出す。
0x0C stloc.2 スタック上の値をインデックス番号2のローカル変数に取り出す。
0x0D stloc.3 スタック上の値をインデックス番号3のローカル変数に取り出す。
0x13 <uint8> stloc.s index スタック上の値をインデックス番号indexのローカル変数に取り出す。indexが0~255以内のとき用。
0x81 <T> stobj class
0x80 <T> stsfld field
0x59 sub
0xDA sub.ovf
0xDB sub.ovf.un
0x45 <uint32> <int32> ... <int32> switch N, t1...tN ジャンプテーブルを作り、評価スタックから取り出した値と一致するインデックスが示すアドレスに飛ぶ。一致するものが無ければ続行する。
0xFE 0x14 tail. 後続のメソッドが実行される直前に、後続のメソッドの引数を除く、現在のメソッドのスタックフレームを削除する。末尾呼び出し最適化用。
0x7A throw 現在の評価スタックにある例外オブジェクトをスローする。
0xFE 0x12 <uint8> unaligned. alignment
0x79 <T> unbox valType
0xA5 <T> unbox.any typeTok
0xFE 0x13 volatile. 後続の命令が使う評価スタック上の値が、揮発性である(複数のスレッドによって変更される可能性がある)ことを指定し、ランタイムによるキャッシュなどを禁止させる。
0x61 xor 評価スタックから2つの整数値と取り出し、ビットごとの排他的論理和を計算し、結果を評価スタックに積む。

関連ツール[編集]

関連項目[編集]

参考文献[編集]

外部リンク[編集]