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文件的运行过程,谢谢。

  • 相关阅读:
    ASP.NET Web API 框架研究 Self Host模式下的消息处理管道
    ASP.NET Web API 框架研究 Web Host模式下的消息处理管道
    ASP.NET Web API 框架研究 核心的消息处理管道
    ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道
    ASP.NET Web API 框架研究 ASP.NET Web API 路由
    ASP.NET Web API 框架研究 ASP.NET 路由
    ASP.NET Web API 入门 (API接口、寄宿方式、HttpClient调用)
    MVVM模式
    RESTful Web API 理解
    C# 函数式编程及Monads.net库
  • 原文地址:https://www.cnblogs.com/brookshi/p/5273281.html
Copyright © 2011-2022 走看看