.Net8罕見的技術:MSIL的機器碼簡析

前言

一般的只有最終的彙編代碼纔有機器碼錶示,然一個偶然的機會發現,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)上,歡迎關注
image

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