來(lái)源:Joye.Net
鏈接:http://www.cnblogs.com/yinrq/p/5486103.html
一,、前言
IL是什么?
Intermediate Language (IL)微軟中間語(yǔ)言
C#代碼編譯過(guò)程,?
C#源代碼通過(guò)LC轉(zhuǎn)為IL代碼,,IL主要包含一些元數(shù)據(jù)和中間語(yǔ)言指令,;
JIT編譯器把IL代碼轉(zhuǎn)為機(jī)器識(shí)別的機(jī)器代碼。如下圖
語(yǔ)言編譯器:無(wú)論是VB code還是C# code都會(huì)被Language Compiler轉(zhuǎn)換為MSIL
MSIL的作用:MSIL包含一些元數(shù)據(jù)和中間語(yǔ)言指令
JIT編譯器的作用:根據(jù)系統(tǒng)環(huán)境將MSIL中間語(yǔ)言指令轉(zhuǎn)換為機(jī)器碼
為什么ASP.NET網(wǎng)站第一次運(yùn)行時(shí)會(huì)較慢,,而后面的執(zhí)行速度則會(huì)相對(duì)快很多,?
當(dāng)你第一次運(yùn)行.NET開(kāi)發(fā)的站點(diǎn)時(shí),CLR會(huì)將MSIL通過(guò)JIT進(jìn)行編譯,,最終轉(zhuǎn)換為執(zhí)行速度非??斓腘ative Code。這可以解釋,。
為什么要了解IL代碼,?
如果想學(xué)好.NET,IL是必須的基礎(chǔ),,IL代碼是.NET運(yùn)行的基礎(chǔ),,當(dāng)我們對(duì)運(yùn)行結(jié)果有異議的時(shí)候,可以通過(guò)IL代碼透過(guò)表面看本質(zhì),;
IL也是更好理解,、認(rèn)識(shí)CLR的基礎(chǔ);
大量的實(shí)例分析是以IL為基礎(chǔ)的,,所以了解IL,,是讀懂他人代碼的必備基礎(chǔ),同時(shí)自己也可以獲得潛移默化的提高,;
二,、如何把ILDasm導(dǎo)入到VS中
想要看IL代碼需要使用ILDasm工具,工具一般在電腦的
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe
也可以下載ILSpy:http:///
把ILDasm導(dǎo)入到VS工具中,,使用方便,,具體如下:工具 - > 外部工具
導(dǎo)入之后,vs工具里面就有ILDasm工具了,。以后想看IL代碼方便多了,。
IL代碼通過(guò)ILDasm反編譯后(左圖),ILDasm圖標(biāo)意義(右圖)
三,、分析IL代碼
在分析IL代碼之前,,要先理解幾個(gè)概念:
圖片來(lái)源:https://msdn.microsoft.com/zh-tw/library/dd229210.aspx Managed Heap(托管堆):這就是NET中的托管堆,用來(lái)存放引用類型,,它是由GC(垃圾回收器自動(dòng)進(jìn)行回收)管理,;
Call Stack(調(diào)用堆棧):調(diào)用堆棧:調(diào)用堆棧是一個(gè)方法列表,按調(diào)用順序保存所有在運(yùn)行期被調(diào)用的方法,。
Evaluation Stack(計(jì)算堆棧):每個(gè)線程都有自己的線程棧,,IL 里面的任何計(jì)算,都發(fā)生在 Evaluation Stack 上,,其實(shí)就是一個(gè) Stack 結(jié)構(gòu),??梢?Push,也可以 Pop,。
可以對(duì)照IL指令:指令列表,,一步一步來(lái)分析IL代碼
1、用C#寫一個(gè)簡(jiǎn)單控制臺(tái)應(yīng)用程序
using System;
namespace ILDemo { class Program { static void Main(string[] args) { int i = 1; int j = 2; int k = 3; int answer = i + j + k; Console.WriteLine('i+j+k=' + answer); Console.ReadKey(); } } }
2,、 用ILDasm打開(kāi)bin下的.exe文件查看代碼,,具體IL代碼如下:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代碼大小 42 (0x2a) .maxstack 2 .locals init ([0] int32 i, [1] int32 j, [2] int32 k, [3] int32 answer) IL_0000: nop IL_0001: ldc.i4.1 IL_0002: stloc.0 IL_0003: ldc.i4.2 IL_0004: stloc.1 IL_0005: ldc.i4.3 IL_0006: stloc.2 IL_0007: ldloc.0 IL_0008: ldloc.1 IL_0009: add IL_000a: ldloc.2 IL_000b: add IL_000c: stloc.3 IL_000d: ldstr 'i+j+k=' IL_0012: ldloc.3 IL_0013: box [mscorlib]System.Int32 IL_0018: call string [mscorlib]System.String::Concat(object, object) IL_001d: call void [mscorlib]System.Console::WriteLine(string) IL_0022: nop IL_0023: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() IL_0028: pop IL_0029: ret } // end of method Program::Main
3、會(huì)用到的IL指令:
nop:無(wú)操作
ret:從當(dāng)前方法返回,,并將返回值(如果存在)從調(diào)用方的計(jì)算堆棧推送到被調(diào)用方的計(jì)算堆棧上,。
call:調(diào)用由傳遞的方法說(shuō)明符指示的方法。
box:將值類轉(zhuǎn)換為對(duì)象引用,,就是裝箱,,同理可以知道拆箱unbox ldc.i4.X:把int32的值推送到計(jì)算堆棧
stloc.X:把計(jì)算堆棧頂部的值放到調(diào)用堆棧索引為X處
ldloc.X:把調(diào)用堆棧X處的值復(fù)制到計(jì)算堆棧
4、理解注釋后的代碼
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint //程序入口 // 代碼大小 42 (0x2a) .maxstack 2 // 計(jì)算出計(jì)算堆棧的能存幾個(gè)值
.locals init ([0] int32 i, [1] int32 j, [2] int32 k, [3] int32 answer) //定義int32類型的i,j,k,answer
IL_0000: nop //無(wú)操作
IL_0001: ldc.i4.1 //把i的值放到計(jì)算堆棧上 IL_0002: stloc.0 //把計(jì)算堆棧頂部的值(i的值)放到調(diào)用堆棧索引0處 IL_0003: ldc.i4.2 //把j的值放到計(jì)算堆棧上 IL_0004: stloc.1 //把計(jì)算堆棧頂部的值(j的值)放到調(diào)用堆棧索引1處 IL_0005: ldc.i4.3 //把k的值放到計(jì)算堆棧上 IL_0006: stloc.2 //把計(jì)算堆棧頂部的值(k的值)放到調(diào)用堆棧索引2處
IL_0007: ldloc.0 //把調(diào)用堆棧索引為0處的值復(fù)制到計(jì)算堆棧 IL_0008: ldloc.1 //把調(diào)用堆棧索引為1處的值復(fù)制到計(jì)算堆棧 IL_0009: add //相加 IL_000a: ldloc.2 //把調(diào)用堆棧索引為2處的值復(fù)制到計(jì)算堆棧 IL_000b: add //相加 IL_000c: stloc.3 //把計(jì)算堆棧頂部的值(add的值)放到調(diào)用堆棧索引3處 IL_000d: ldstr 'i+j+k=' //推送對(duì)元數(shù)據(jù)中存儲(chǔ)的字符串的新對(duì)象引用,。 IL_0012: ldloc.3 //把調(diào)用堆棧索引為3處的值復(fù)制到計(jì)算堆棧
IL_0013: box [mscorlib]System.Int32 //裝箱 IL_0018: call string [mscorlib]System.String::Concat(object,object) //調(diào)用內(nèi)部方法 IL_001d: call void [mscorlib]System.Console::WriteLine(string) //調(diào)用WriteLine IL_0022: nop //無(wú)操作 IL_0023: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() //調(diào)用ConsoleKey IL_0028: pop //無(wú)操作 IL_0029: ret //return } // end of method Program::Main
|