http://kb.cnblogs.com/page/104481/
摘要:對於一個已編譯好的.NET程式集,Windows作業系統是如何啟動執行的呢?
對於一個已編譯好的.NET程式集,Windows作業系統是如何啟動執行的呢?日常使用中我們發現對於託管的和非託管的程式集編譯器都會吧程式集編譯成以.exe或.dll等為副檔名的檔案,可見Windows載入器並沒有區分是託管還是非託管的程式集,而且我們也知道對非託管的程式集是在編譯器直接編譯成了機器碼,自然可以由CPU直接執行,而託管的.NET 程式集是包含複雜結構的MSIL代碼,執行時會使用JIT即時編譯器將IL代碼編譯成機器碼,再由CPU執行,當然這期間還需要執行其它許多的工作,如載入CLR、執行初始化等工作,那麼這些是怎麼自動實現的呢?
理解這些問題是我們深入.NET的關鍵,由於日常的開發工作並不涉及這些知識(編譯器已經給我們做了),結果是很多的.NET 書忽略了這一點,也很少有人研究者方面的內容,所以在閱讀了《.NET 進階調試》這本書給了我非常清晰地認識,把裡面的這方面精彩的內容做了一個總結以供那些還沒有清楚.NET 程式集如何執行的學者們一個簡單的參考。
首先我們要清楚的是對於託管還是非託管程式集,他們在編譯器執行編譯時間都會編譯成一個特殊的檔案格式,即PE檔案(可攜式執行檔格式),作業系統載入器通過載入這樣的PE檔案來執行程式集的。可以這麼說吧,無論是託管程式還是非託管程式他們實際上都是編譯成這樣的PE檔案(只是有部分內容不一樣而已)。
然後這個PE檔案會指示如何執行託管程式集和非託管程式集,載入器首先會尋找到PE頭中的AddressOfEntryPoint域,這個域指示PE檔案的進入點位置,在.NET程式集中是指向.text段中的CLR頭--〉包含一個結構IMAGE_COR20_HEADER—包含許多資訊如Managed 程式碼應用程式的進入點,目標CLR的主要版本號和從版本號碼,以及程式集的強式名稱簽名等--〉Windows載入器根據這個資料結構決定載入哪個版本的CLR以及一些基本的程式集資訊。在.text段中還包含了程式集的中繼資料表,MSIL以及非託管啟動存根代碼,而非託管啟動存根程式碼封裝好了由Windows載入器執行役啟動PE檔案執行的代碼,結構。
這樣.NET 程式集的載入演算法包括:
1、使用者執行一個.NET程式集;
2、Windows載入器查看AddressOfEntryPoint域,並找到PE映像檔案的.text段;
3、位於AddressOfEntryPoint位置上的位元組只是一個JMP(跳轉)指令,這個指令跳轉到mscoree.dll中的一個匯入函數;
4、將執行控制轉移到mscoree.dll中的_CorExeMain中,這個函數將啟動CLR並把執行控制轉移到程式集的進入點。