閱讀IL主要是為了能夠更好的學會Emit 從控制台開始吧:事先準備工具ILSpy,和IL的命令指南(這個可以網上搜索或者去看OpCode枚舉),記住棧中的都是引用的地址 int i = 10; int j = 20; int k = 30; Console.WriteLine(i + j + k); ...
閱讀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:從當前方法返回,並將返回值(如果存在)從調用方的計算堆棧推送到被調用方的計算堆棧上。
因緣際會的相遇,自當有非同尋常的結局 QQ交流群:110826636