[你必須知道的.NET]第十三回:從Hello, world開始認識IL

來源:互聯網
上載者:User

發布日期:2007.7.22 作者:Anytao

2007 Anytao.com ,原創作品,轉貼請註明作者和出處。

本文將介紹以下內容:

  • IL程式碼分析方法 
  • Hello, world曆史 
  • .NET學習方法論

 

1. 引言

1988年Brian W. Kernighan和Dennis M. Ritchie合著了軟體史上的經典巨著《The C programming Language》,我推薦所有的程式人都有機會重溫這本曆史上的經典之作。從那時起,Hello, world樣本就作為了幾乎所有實踐型程式設計書籍的開篇代碼,一直延續至今,除了表達對巨人與曆史的尊重,本文也以Hello, world樣本作為我們扣開IL語言的起點,開始我們循序漸進的IL認識之旅。

2. 從Hello, world開始

首先,當然是展示我們的Hello, world代碼,開始一段有益的分享。

using System;
using System.Data;

public class HelloWorld
{
    public static void Main()
    {
        Console.WriteLine("Hello, world.");
    }
}

這段代碼執行了最簡單的過程,向陌生的世界打了一個招呼,那麼運行在進階語言背後真相又是什麼呢,下面開始我們基於上述樣本的IL程式碼分析。 

3. IL體驗中心

對編譯後的可執行檔HelloWorld.exe應用ILDasm.exe反編譯工具,還原HelloWorld的為文本MSIL編碼,至於其工作原理我們期望在系列的後續文章中做以交代,我們查看其為:

 

 

由可知,編譯後的IL結構中,包含了MANIFEST和HelloWorld類,其中MANIFEST是個附加資訊列表,主要包含了程式集的一些屬性,例如程式集名稱、版本號碼、雜湊演算法、程式集模組等,以及對外部參考程式集的引用項;而HelloWorld類則是我們下面介紹的主角。

3.1 MANIFEST清單分析

開啟MANIFEST清單,我們可以看到

從這段IL代碼中,我們的分析如下:

  • .assembly指令用於定義編譯目標或者載入外部庫。在IL清單中可見,.assembly extern mscorlib表示外部載入了外部核心庫mscorlib,而.assembly HelloWorld則表示了定義的編譯目標。值得注意的是,.assembly將只顯示程式中實際應用到的程式集列表,而對於加入using引用的程式集,如果並未在程式中引用,則編譯器會忽略多載入的程式集,例如System.Data將被忽略,這樣就有效避免了過度載入引起的代碼膨脹。
  • 我們知道mscorlib.dll程式集定義managed code依賴的核心資料類型,屬於必須附加元件。 例如接下來要分析的.ctor指令表示建構函式,從代碼中我們知道沒有為HelloWord類提供任何顯示的建構函式,因此可以肯定其繼承自基類System.Object,而這個System.Object就包含在mscorlib程式集中。
  • 在外部指令中還會指明了引用版本(.ver);應用程式實際公開金鑰標記(.publickeytoken),公開金鑰Token是SHA1雜湊碼的低8位位元組的反序(如所示),用於唯一的確定程式集;還包括其他資訊如語言文化等。

 

  • HelloWorld程式集中包括了.hash algorithm指令,表示實現安全性所使用的雜湊演算法,系統預設為0x00008004,表明為SHA1演算法;.ver則表示了HelloWorld程式集的版本號碼;
  • 程式集由模組組成, .module為程式集指令,表明定義的模組的中繼資料,以指定當前模組。
  • 其他的指令還有:imagebase為影像基地址;.file alignment為檔案對齊數值;.subsystem為串連系統類別型,0x0003表示從控制台運行;.corflags為設定運行庫標頭檔標誌,預設為1;這些指令不是我們研究的重點,詳細的資訊請參考MSDN相關資訊。

3.2 HelloWorld類分析

首先是HelloWorld類,代碼為:

.class public auto ansi beforefieldinit HelloWorld
       extends [mscorlib]System.Object
{
} // end of class HelloWorld
  • .class表明了HelloWorld是一個public類,該類繼承自外部程式集mscorlib的System.Object類。
  • public為存取控制許可權,這點很容易理解。
  • auto表明程式載入時記憶體的布局是由CLR決定的,而不是程式本身
  • ansi屬性則為了在沒有被管理和被管理代碼間實現無縫轉換。沒有被管理的代碼,指的是沒有運行在CLR運行庫之上的代碼,例如原來的C,C++代碼等。
  • beforefieldinit屬性為HelloWorld提供了一個附加資訊,用於標記運行庫可以在任何時候執行類型建構函式方法,只要該方法在第一次訪問其靜態欄位之前執行即可。如果沒有beforefieldinit則運行庫必須在某個精確時間執行類型建構函式方法,從而影響效能最佳化,詳細的情況可以參與MSDN相關內容。 

然後是.ctor方法,代碼為:

.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // 代碼大小       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ret
} // end of method HelloWorld::.ctor
  • cil managed 說明方法體中為IL代碼,指示編譯器編譯為Managed 程式碼。
  • .maxstack表明執行建構函式.ctor期間的評估堆棧(Evaluation Stack)可容納資料項目的最大個數。關於評估堆棧,其用於儲存方法所需變數的值,並在方法執行結束時清空,或者儲存一個傳回值。
  • IL_0000,是一個標記程式碼開頭,一般來說,IL_之前的部分為變數的聲明和初始化。
  • ldarg.0 表示裝載第一個成員參數,在執行個體方法中指的是當前執行個體的引用,該引用將用於在基類建構函式中調用。
  • call指令一般用於調用靜態方法,因為靜態方法是在編譯期指定的,而在此調用的是建構函式.ctor()也是在編譯期指定的;而另一個指令callvirt則表示調用執行個體方法,它的調用過程有異於call,函數的調用是在運行時確定的,首先會檢查被調用函數是否為虛函數,如果不是就直接調用,如果是則向下檢查子類是否有重寫,如果有就調用重寫實現,如果沒有還調用原來的函數,依次類推直到找到最新的重寫實現。
  • ret表示執行完畢,返回。

最後是Main方法,代碼為:

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // 代碼大小       11 (0xb)
  .maxstack  8
  IL_0000:  ldstr      "Hello, world."
  IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000a:  ret
} // end of method HelloWorld::Main
  • .entrypoint指令表明了CLR載入程式HelloWorld.exe時,是首先從.entrypoint方法開始執行的,也就是表明Main方法將作為程式的入口函數。每個託管程式必須有並且只有一個進入點。這區別於將Main函數作為程式入口標誌。
  • ldstr指令表示將字串壓棧,"Hello, world."字串將被移到stack頂部。CLR通過從中繼資料表中獲得文字常量來構造string對象,值得注意的是,在此構造string對象並未出現在《第五回:深入淺出關鍵字---把new說透》中提到的newobj指令,對於這一點的解釋我們將在下一回中做簡要分析。
  • hidebysig屬性用於表示如果當前類作為父類時,類中的方法不會被子類繼承,因此HelloWorld子類中不會看到Main方法。

接下來的一點補充:

  • 關於注釋,IL代碼中的注釋和C#等進階語言的注釋相同,其實編譯器在編譯IL代碼時已經將所有的注釋去掉,所以任何對程式的注釋在IL代碼中是看不見的。 

3.3 迴歸簡潔

去粗取精,我們的IL代碼可以簡化,下面的代碼是基於上面的分析,並去處不重要的資訊,以更簡潔的方式來展現的HelloWorld版IL代碼,詳細的分析就以注釋來展開吧。

4. 結論

結束本文,我們從一個點的角度和IL來了一次接觸,除了瞭解幾個重要的指令含義,更重要的是已經走進了IL的世界。通過一站式的掃描HelloWorld的IL編碼,我們還不足以從全域來瞭解IL,不過第一次的親密接觸至少讓我們太陌生,而且隨著系列文章的深入我們將逐漸建立起這種認知,從而提高我們掌握瞭解.NET底層的有效工具。本系列也將在後續的文章中,逐漸建立起這種使用工具的方法,敬請關注。

 

 

參考文獻

(USA)Joe Duffy , Professional .NET Framework 2.0

(USA)David Chappell, Understanding .NET

 

CLR團隊公告

CLR基礎研究團隊成立了,本團隊以研究和探求CLR基礎和.NET Framework底層知識為宗旨,在此熱烈的歡迎部落格園的朋友們。如果對CLR及.NET底層研究有興趣,請申請加入CLR基礎研究團隊,在一個專註的環境裡共用你的技術。在申請之前請您閱讀團隊綱領,CLR團隊資訊如下:

團隊地址:http://clr.cnblogs.com/
團隊綱領:查看
團隊申請:進入

團隊近期活動:整理收集團隊成員CLR系列文章,在團隊公告展播。 

溫故知新

[開篇有益]
[第一回:恩怨情仇:is和as]
[第二回:對抽象編程:介面和抽象類別]
[第三回:曆史糾葛:特性和屬性]
[第四回:後來居上:class和struct]
[第五回:深入淺出關鍵字---把new說透]
[第六回:深入淺出關鍵字---base和this]
[第七回:品味類型---從一般型別系統開始]
[第八回:品味類型---實值型別與參考型別(上)-記憶體有理]
[第九回:品味類型---實值型別與參考型別(中)-規則無邊]
[第十回:品味類型---實值型別與參考型別(下)-應用征途]
[第十一回:參數之惑---傳遞的藝術(上)]
[第十二回:參數之惑---傳遞的藝術(下)]

2007 Anytao.com

原創作品,轉貼請註明作者和出處,留此資訊。

本貼子以“現狀”提供且沒有任何擔保,同時也沒有授予任何權利。
This posting is provided "AS IS" with no warranties, and confers no rights.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.