程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> C#代碼運行原理

C#代碼運行原理

編輯:C#基礎知識
你的C#代碼是怎麼跑起來的(一)

寫了那麼多C#代碼,大家有沒有想過自己寫的代碼編譯後的可執行文件內部是什麼樣子,是怎樣在系統上運行的?

編譯成exe,然後雙擊exe文件運行,這中間到底發生了些什麼呢,這篇先來剖析下exe內部的樣子:

我們知道C#代碼編譯後的結果是IL(Intermedidate Language),那生成的exe文件裡面都是IL嗎,當然不會。

C#生成的exe既然是window下可執行文件,那也就是標准的PE文件,和普通win32的exe文件格式一樣。我們來看下exe文件的格式:

dll文件本質上和exe一樣,只是少了入口函數。

MS-DOC MZ Header和MS-DOS Stub是為了兼容DOS系統存在的,目的是使這個exe在DOS下執行時彈出一個提示"This program cannot be run in DOS mode"。

PE Header包含了這個文件的一些信息,如:文件創建日期,文件類型,Section的數量,Optional Header的大小等等。詳細可以參考Winnt.h裡的結構_IMAGE_FILE_HEADER。

PE Optional Header則包含了文件的版本號以及重要的基地址和AddressOfEntryPoint(RVA-Relative Virtual Address),這是程序執行的入口地址,雙擊exe後就從這裡開始執行。對C#程序來說,這裡指向的是.net的核心庫MsCorEE.dll的_CorExeMain()函數。當然這是針對XP系統的,XP以後的系統,OS Loader已經可以判斷出這個PE是否包含CLR頭來決定是否運行MsCorEE.dll的_CorExeMain()函數。

Section有很多,包括代碼節,數據節等,C#程序會把CLR頭,元數據,IL放在這裡面。

CLR是什麼呢,全稱Common Language Runtime,公共語言運行時,CLR主要是管理程序集,托管堆內存,異常處理和線程同步等等。

CLR頭具體可以參考CorHdr.h中的IMAGE_COR20_HEADER結構,如下:

 typedef struct IMAGE_COR20_HEADER
     {
         // CLR版本信息
         ULONG cb;
         USHORT MajorRuntimeVersion;
         USHORT MinorRuntimeVersion;
 
         IMAGE_DATA_DIRECTORY MetaData; //元數據
         ULONG Flags;
         ULONG EntryPointToken;  //入口函數Main的標識
 
 
         IMAGE_DATA_DIRECTORY Resources;  //資源
         IMAGE_DATA_DIRECTORY StrongNameSignature;  //強名稱標識
 
 
         // Regular fixup and binding information
         IMAGE_DATA_DIRECTORY CodeManagerTable;
         IMAGE_DATA_DIRECTORY VTableFixups;
         IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
 
         // Precompiled image info (internal use only - set to zero)
         IMAGE_DATA_DIRECTORY ManagedNativeHeader;
 
     }
     IMAGE_COR20_HEADER;

元數據很重要,驗證代碼類型安全,GC的對象引用跟蹤還有我們常用的反射都需要用到元數據。

元數據主要由定義表,引用表,清單表組成。

定義表包括應用所有的類型,方法,字段,屬性,參數,事件的定義,代碼裡任何的定義項都可以在這個表裡找到,反射就是靠這個表只要一個名字就能得到屬性或函數。運行時的類型安全檢查也離不開它。

引用表包括程序集,類型和成員的引用,我們知道GC在回收內存時先默認認為所有對象都是垃圾,然後通過線程棧上的根(cpu寄存器,局部變量,參數,靜態變量)找引用的對象,能找到的說明還在使用就去掉垃圾標記,這個表可以讓GC在回收內存時方便從根找到所有引用。

清單表主要是程序集,文件,資源的定義。

IL就不多說了,不了解的朋友可以參考小弟的另一篇文章:30分鐘?不需要,輕松讀懂IL

元數據和IL都可以通過工具ildasm.exe來查看。

以上就是C#生成的exe文件的主要結構,下篇再講exe文件的運行過程,謝謝。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved