kazuk は null に触れてしまった

C# / .NET 系技術ネタ縛りでお送りしております

普通の人は全く知らないでもいい MSIL の基礎知識


 

.NET基礎勉強会 http://connpass.com/event/2441/ で ILについてお話させていただく事になったんですが、まぁ 30分枠ぐらいだと、だいぶ話せる事が限られるんで、あらかじめ Blog に記事乗せといた方が良いかなー的に書いておきます。

 

「手元にございますMSIL命令表をご覧ください」 「えっ、どこよ?」

.NET Framework がインストールされている環境であれば、MSIL命令表は入っています。mscorlibアセンブリ、 System.Refrection.Emit 名前空間配下の OpCodes クラスのOpCode型フィールドをリフレクションで舐めてください。

命令表としての活用の仕方にもよりますが、プレフィックスバイト等も命令表には入っています (Prefix1 etc)、自分の用途でプレフィックスとか要らない場合には、そういう物をフィルタしてあげましょう。 OpCode の OpCodeType を見ればそれがプレフィックスなのか判別する事ができます。

MSIL バイト列の見かた

さて、MSILバイト列の見かたです。バイト列そのものは実行時にリフレクションで取るならば、 MethodInfo から MethodBody を引き、MethodBody から GetILAsByteArray メソッドで取得する事ができます。

このバイト列に各 IL 命令がどのように入っているかです。

オペコード

まず、IL オペコードには 1バイトと 2バイトがあります。

命令のサイズは OpCodes を舐めているならば、OpCode の Size プロパティから取得できます。 これが 1の物は 1バイト命令で、2の物は2バイト命令です。

オペコードの値そのものは OpCode 構造体の Value プロパティに入っています。

2バイトのオペコードはMSILバイト列にビッグエンディアンのバイト順で入ります。要するに 0xDEAD の Value を持つ命令のオペコードが 0xDE 0xAD の順でILバイト列に入ります。(1バイトのプレフィックス命令と、1バイト命令がつながって入っているともいえます。) ※ MSILバイト列で唯一のビッグエンディアンです、他はすべてリトルエンディアンになっています。

1バイトオペコード命令

OpCode オペランド(無い場合もある)

2バイトオペコード命令

Prefix
OpCode
OpCode
(LowByte)
オペランド(無い場合もある)

オペランド

オペランドはオペコードによりますが、 OpCode 構造体の OperandType で取得できます。

OperandType の switch だけが特殊ですが、それ以外は単純にオペランドのサイズは固定されています。そのバイト数分をリトルエンディアンとして読みだせばオペランド値として使える値を普通に取得する事ができます。

OperandType が switch の場合、switch のオペランドにはラベル数が入ります、ラベル数分 InlineBrTarget がバイト列に入ります。

ブランチオフセットの起点

ブランチオフセットの起点はブランチ命令の次の命令です。

たとえば IL Offset n に ShortInlineBrTarget で 3 を指定する1バイトのブランチ命令があった場合、 n +1 (opcode size ) +1 (operand size) がブランチオフセットの起点となり、n +1 (opcode size ) +1 (operand size) + 3(operand value) がブランチ先のIL Offset になります。

ILの動作フローを変える物はブランチ命令と、ret、throwとそれに関連する例外処理ぐらいしかありません。ブランチ命令のオフセットを解釈できるようになった今あなたはILのコントロールフロー解析ができるようになったという事です。

まとめ

7/20 日に話す事はここから後の話ですって事で、MSILの基礎の基礎でした。

7/20 日にはMSILの評価スタックと例外フレームについて話したいと思っているのですが、時間枠的に評価スタックの話で一杯かもしれません。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。