.Net——元数据和IL

CS代码编译成IL

在这里插入图片描述
在这里插入图片描述

  • cs代码编译之后将生成元数据和IL,并组成托管模块(Module)的基本单元。
  • 多个托管模块组成程序集,其实还包括一定的资源文件,例如图标、图片、文本信息等。
  • 程序集或者可执行文件是逻辑组织的基本单元,符合基本的Windows PE文件格式,可以被x86或者x64 Windows直接加载执行。

一个或者多个模块,再加上资源文件就形成了程序集(Assembly),作为逻辑组织的基本单元
在这里插入图片描述
仅仅从粗粒度对程序集的基本组成有个大致的了解,实际上程序集中包含了更复杂的结构和要素,例如PE Signature、Managed Resources、Strong Name Signature Hash,其中最核心的要素则体现在图中。

  • 程序集清单(MANIFEST)包含了程序集的自描述信息,主要包含AssemblyDef、FileDef、ManifestResourceDef和ExportedTypeDef,在反编译选项中MANIFEST包含了详细的内容。本书4.1节“从Hello,world开始认识IL”对其有过详细的描述,在此不再赘述。
  • PE文件头,标准Windows PE头文件(PE32或PE32+),PE文件的基本信息,例如文件类型、创建时间、本地CPU信息等。
  • CLR头,包含CLR版本、模块元数据、资源等信息。
  • 元数据。
  • IL。
  • 资源文件。
    在这里插入图片描述
    Class Two 编译后的IL代码

元数据

元数据,就是描述数据的数据。这一概念并非CLR之独创,Metadata存在于任何对数据和数据关系的描述中,例如程序集清单信息也被称为程序集元数据。另外,一个完备的平台性系统(例如,Microsoft Dynamic CRM系统),基于功能性和扩展性的考量,也往往具有自定义的元数据系统,以描述其类型、界面、关系还有配置等基础信息。

.NET是基于面向对象的,所以元数据描述的主要目标就是面向对象的基本元素:类、类型、属性、方法、字段、参数、特性等,主要包括:
●定义表,描述了源代码中定义的类型和成员信息,主要包括:TypeDef、MehodDef、FieldDef、ModuleDef、PropertyDef等。
●引用表,描述了源代码中引用的类型和成员信息,引用元素可以是同一程序集的其他模块,也可以是不同程序集的模块,主要包括:AssemblyRef、TypeRef、ModuleRef、MethodsRef等。
●指针表,使用指针表引用未知代码,主要包括:MethodPtr、FieldPtr、ParamPtr等。
●堆,以stream的形式保存的信息堆,主要包括:#String、#Blob、#US、#GUIDe等。

元数据是保存了类型的编译后数据,是.NET程序运行的基础,我们可以在运行时动态地以反射的方式获取元数据信息,而这些信息在.NET Framework中以System.Type、MethodInfo等封装。

元数据表类似数据库表,有主键和Sechema,元数据表以RID(表索引)和元-元数据表示类同的概念。

IL

IL,又称为CIL或者MSIL,翻译为中文就是中间语言,由ECMA组织(Standard ECMA-335)提供完整的定义和规范。顾名思义,任何与CLR兼容的编译器所生成的都是中间语言代码,这是实现CLR跨语言的基础结构之一。IL就像一座桥梁,其指令集独立于CPU指令而存在,可以由JIT编译器在运行时翻译为本地代码执行,连接了任何遵守CLS规范的高级语言,为.NET平台提供了最基本的支持。

Metadata描述了静态的结构,而IL阐释了动态的执行。

IL引用元数据

IL代码是通过一个4字节大小的地址引用元数据表的。该引用被称为元数据符号(Metadata Token,也就是记录元数据表的位置信息)。
在这里插入图片描述
元数据第一个字节表示引用的元数据表,而其余三个字节则表示在相应元数据表中的记录,例如06000003表示引用了MethodDef(06)表的000003项Main方法。

可以通过Type的MetadataToken属性在运行时反射获取类型的元数据符号
在这里插入图片描述

元数据和IL在JIT编译时

CLR最终执行的只有本地机器码,所以JIT编译的作用是在运行时将IL代码解析为机器码执行。
首先,IL是基于栈执行的,执行方法调用时,方法参数、局部变量还有返回值等被分配于栈上,并执行其调用过程,既然是关注JIT编译时,我们自然而然将关注方法的执行,因为JIT编译是以执行方法调用而触发的。
在这里插入图片描述
在这里插入图片描述
以该例而言,执行Main方法调用时,同时伴随着对于Three实例的创建和相应类型信息的加载。类型加载一定是在实例创建之前完成的,也就是我们常常提起的方法表创建。类型加载是由class loader负责执行的,其过程简而言之就是从元数据表中获取相应的类型信息,创建方法表(包含CORINFO_CLASS_STRUCT结构),其结构主要包括非虚方法表和虚方法表,按照继承的虚方法、新引入的虚方法、实例方法和静态方法的顺序排列,以类Three类型为例其CORINFO_CLASS_STRUCT结构可以表示如图所示的形式。在这里插入图片描述

ClassLoader进行类型加载,从元数据表中获取类型信息 -> 创建方法表 -> 创建实例

执行细则

  1. class loader从TypeDef元数据表加载相关元数据信息,包括当前类型、继承层次的所有父类和实现的接口元数据,根据这些信息建立CORINFO_CLASS_STRUCT结构在这里插入图片描述
    Class Loader是CLR提供的基本组件之一,作用正像其名称所宣扬的那样,load一个Class给CLR,class loader将Metadata和IL从PE文件中取出,并加载到运行时内存,简单地说就是我们下面要介绍的全过程缩影。

  2. 加载之后,方法执行之前的CORINFO_CLASS_STRUCT中所有的方法表槽都保存了方法应该执行的行为逻辑,这些信息保存在被称为方法描述(MethodsDesc)的结构中,而MethodDesc则被初始化为指向IL代码,同时还包含一个指向触发JIT编译的PreJitStub地址,如图所示。在这里插入图片描述

  3. 任何方法第一次执行时都会首先触发执行JIT编译,JIT的主要工作就是将IL代码翻译为Native Code,并插入指向Native Code的jmp指令地址覆盖原来的Call JIT Compiler指令在这里插入图片描述

  4. 当该方法再次被执行时,因为MethodDesc中保存了机器码地址,以后的执行将不会执行JIT编译过程而直接执行x86(X64)机器码,实现整个执行过程。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值