前言
一般的只有最終的彙編代碼纔有機器碼錶示,然一個偶然的機會發現,MSIL(Microsoft intermediate language)作爲一箇中間語言表示,居然也有機器碼,其實這也難怪,計算機裏面萬物都是二進制,本篇來看下,以下以.Net8 PreView Source Code分析爲主。原文:在此處
概括
1.C# And IL
先上C#代碼:
static void Main()
{
Program pm=new Program();
GC.Collect();
Console.WriteLine("CeShi JITDUMP");
Console.ReadLine();
}
非常簡單的一段代碼,把這段代碼編譯後的DLL導入到微軟官方的ILDASM工具裏面去,可以看到如下代碼:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// 代碼大小 28 (0x1c)
.maxstack 8
IL_0000: newobj instance void Program::.ctor()
IL_0005: pop
IL_0006: call void [System.Runtime]System.GC::Collect()
IL_000b: ldstr "CeShi JITDUMP"
IL_0010: call void [System.Console]System.Console::WriteLine(string)
IL_0015: call string [System.Console]System.Console::ReadLine()
IL_001a: pop
IL_001b: ret
} // end of method Program::Main
這裏注意下標號IL_0000的那段代碼:
IL_0000: newobj instance void Program::.ctor()
以此爲例子作爲觀察。
2.JIT Import IL
來看下JIT把這段IL代碼導入後的一個情況
IL to import:
IL_0000 73 04 00 00 06 newobj 0x6000004
IL_0005 26 pop
IL_0006 28 0e 00 00 0a call 0xA00000E
IL_000b 72 01 00 00 70 ldstr 0x70000001
IL_0010 28 0f 00 00 0a call 0xA00000F
IL_0015 28 10 00 00 0a call 0xA000010
IL_001a 26 pop
IL_001b 2a ret
注意到JIT導入這段IL代碼之後,多了機器碼,多了十六進制的表示。以IL_0000段代碼爲例
導入之前:
IL_0000: newobj instance void Program::.ctor()
這裏newobj之前沒有機器碼,newobj之後是調用了函數instance void Program::.ctor()。
導入之後:
IL_0000 73 04 00 00 06 newobj 0x6000004
這裏很明顯看到變化,newobj之前有一連串的機器碼:73 04 00 00 06。newobj之後,則有十六進制0x6000004取代了上面的函數調用:instance void Program::.ctor()。
3.分析
那麼IL裏面的這些機器碼和十六進制數值是幹什麼用的呢?
首先看下機器碼:73 04 00 00 06。一個個的看。
最先的0x73,它表示的是:newobj的機器碼。它的原型是:
OPDEF(CEE_NEWOBJ, "newobj",VarPop,PushRef,InlineMethod, IObjModel, 1,0xFF,0x73,CALL)
後面的04 00 00 06這四個字節的機器碼可以看做一個整體,小端取值那麼它的值是:6000004。
那麼這個6000004到底表示什麼東西呢?通過ILDASM的快捷鍵Ctrl+M打開元數據信息,裏面可以看到6000004表示的就是.ctor函數的元數據描述,它的原型如下:
Method #2 (06000004)
-------------------------------------------------------
MethodName: .ctor (06000004)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor] (00001886)
RVA : 0x00002084
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
那麼這段代碼
IL_0000 73 04 00 00 06 newobj 0x6000004
的整體意思就很清楚了,73 04 00 00 06裏面的73是表示newobj,後面的04 00 00 06表示調用.ctor非靜態構造函數。它實際上跟ILDASM裏面顯示的IL代碼是同一個意思,但是因爲在內存裏面操作,所以它只能是十六進制或者二進制,JIT導入的時候只不過把字母的含義替換成了具體數字的含義。其它的IL代碼依次類推。
結尾
作者:江湖評談
文章首發在公衆號(jianghupt)上,歡迎關注