zoukankan      html  css  js  c++  java
  • 你的C#代码是怎么跑起来的(一)

    写了那么多C#代码,大家有没有想过自己写的代码编译后的可执行文件内部是什么样子,是怎样在系统上运行的?

    编译成exe,然后双击exe文件运行,这中间到底发生了些什么呢,这篇先来剖析下exe内部的样子:

    我们知道C#代码编译后的结果是IL(Intermediate 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结构,如下:

     1 typedef struct IMAGE_COR20_HEADER
     2     {
     3         // CLR版本信息
     4         ULONG cb;
     5         USHORT MajorRuntimeVersion;
     6         USHORT MinorRuntimeVersion;
     7 
     8         IMAGE_DATA_DIRECTORY MetaData; //元数据
     9         ULONG Flags;
    10         ULONG EntryPointToken;  //入口函数Main的标识
    11 
    12 
    13         IMAGE_DATA_DIRECTORY Resources;  //资源
    14         IMAGE_DATA_DIRECTORY StrongNameSignature;  //强名称标识
    15 
    16 
    17         // Regular fixup and binding information
    18         IMAGE_DATA_DIRECTORY CodeManagerTable;
    19         IMAGE_DATA_DIRECTORY VTableFixups;
    20         IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
    21 
    22         // Precompiled image info (internal use only - set to zero)
    23         IMAGE_DATA_DIRECTORY ManagedNativeHeader;
    24 
    25     }
    26     IMAGE_COR20_HEADER;

    元数据很重要,验证代码类型安全,GC的对象引用跟踪还有我们常用的反射都需要用到元数据。

    元数据主要由定义表,引用表,清单表组成。

    定义表包括应用所有的类型,方法,字段,属性,参数,事件的定义,代码里任何的定义项都可以在这个表里找到,反射就是靠这个表只要一个名字就能得到属性或函数。运行时的类型安全检查也离不开它。

    引用表包括程序集,类型和成员的引用,我们知道GC在回收内存时先默认认为所有对象都是垃圾,然后通过线程栈上的根(cpu寄存器,局部变量,参数,静态变量)找引用的对象,能找到的说明还在使用就去掉垃圾标记,这个表可以让GC在回收内存时方便从根找到所有引用。

    清单表主要是程序集,文件,资源的定义。

    IL就不多说了,不了解的朋友可以参考小弟的另一篇文章:30分钟?不需要,轻松读懂IL

    元数据和IL都可以通过工具ildasm.exe来查看。

    以上就是C#生成的exe文件的主要结构,下篇再讲exe文件的运行过程,谢谢。

  • 相关阅读:
    gitment Error:validation failed错误解决办法
    Hexo博客yilia主题添加Gitment评论系统
    用DateTime的ParseExact方法解析特殊的日期时间
    C#中的日期处理函数
    SQL,Linq,Lambda之间的转换练习
    Windows Azure Platform 系列文章目录
    Linq查询表达式
    EF框架的三种工作方式
    jQuery UI 实现图片循环显示,常用于网站首页banner广告切换
    jQuery UI Datepicker
  • 原文地址:https://www.cnblogs.com/brookshi/p/5273281.html
Copyright © 2011-2022 走看看