IL閱讀第一篇,簡單的加法

閱讀IL主要是爲了能夠更好的學會Emit

從控制檯開始吧:事先準備工具ILSpy,和IL的命令指南(這個可以網上搜索或者去看OpCode枚舉),記住棧中的都是引用的地址

int i = 10;
            int j = 20;
            int k = 30;
            Console.WriteLine(i + j + k);
            Console.ReadKey();

編譯後查看IL

	.maxstack 2
	.entrypoint
	.locals init (
		[0] int32 i,
		[1] int32 j,
		[2] int32 k
	)

	IL_0000: nop
	IL_0001: ldc.i4.s 10
	IL_0003: stloc.0
	IL_0004: ldc.i4.s 20
	IL_0006: stloc.1
	IL_0007: ldc.i4.s 30
	IL_0009: stloc.2
	IL_000a: ldloc.0
	IL_000b: ldloc.1
	IL_000c: add
	IL_000d: ldloc.2
	IL_000e: add
	IL_000f: call void [mscorlib]System.Console::WriteLine(int32)
	IL_0014: nop
	IL_0015: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
	IL_001a: pop
	IL_001b: ret

  解釋如下:

第一段:

     .maxstack 2
    .entrypoint
    .locals init (
        [0] int32 i,
        [1] int32 j,
        [2] int32 k
    )

這段代碼是定義一個深度爲2的棧,然後初始化三個變量都內存

第二段:

     IL_0000: nop
    IL_0001: ldc.i4.s 10
    IL_0003: stloc.0
    IL_0004: ldc.i4.s 20
    IL_0006: stloc.1
    IL_0007: ldc.i4.s 30
    IL_0009: stloc.2

這段代碼nop是:如果修補操作碼,則填充空間。儘管可能消耗處理週期,但未執行任何有意義的操作。(我想,這也許就是可以優化掉的)

然後ldc.i4.s:將提供的 int8 值作爲 int32 推送到計算堆棧上(短格式)。大致就是將一個靜態的數值推送到計算堆棧上,這裏是將10推送上去,壓入棧中。

接着stloc.0:從計算堆棧的頂部彈出當前值並將其存儲到索引 0 處的局部變量列表中。在棧頂部彈出10到變量中。

一下20和30都是同上。

第三段:

    IL_000a: ldloc.0
    IL_000b: ldloc.1
    IL_000c: add
    IL_000d: ldloc.2
    IL_000e: add

這段代碼ldloc.0:將索引 0 處的局部變量加載到計算堆棧上。

意思是壓入第一個變量到棧,壓入第二個變量到棧,然後執行add操作。add操作是將棧頂部前兩個彈出執行,再將得到的數壓入棧。

然後就是索引三,也就是第三個變量壓入到棧,接着在執行add,將結果壓入棧。現在爲止,棧中只有一個量。

第四段:

 IL_000f: call void [mscorlib]System.Console::WriteLine(int32)
 IL_0014: nop

彈出棧的第一個量,執行System.Console下的WriteLine函數,

第五段:

     IL_0015: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_001a: pop

ReadKey()沒有參數,直接執行。

第六段:

 IL_001b: ret

ret:從當前方法返回,並將返回值(如果存在)從調用方的計算堆棧推送到被調用方的計算堆棧上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章