「共通中間言語」の版間の差分
imported>Fallout New Tokyo 編集の要約なし |
imported>Fallout New Tokyo 編集の要約なし |
||
| 34行目: | 34行目: | ||
default void Main(string[] args) cil managed | default void Main(string[] args) cil managed | ||
{ | { | ||
// | // どうみてもエントリポイント | ||
.entrypoint | .entrypoint | ||
.maxstack 8 | .maxstack 8 | ||
2014年2月27日 (木) 02:41時点における版
共通中間言語(読み:きょうつうちゅうかんげんご、英語: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つの整数値と取り出し、ビットごとの排他的論理和を計算し、結果を評価スタックに積む。 |