CLR - 基础
前言
好记性不如烂“笔头”系列。。。
目录
托管模块
面向 CLR 的编译器在编译源文件时最终会编译成一个 PE(可移植执行体 , Portable Executable) 文件 .
而一个托管模块的组成由下面几个部分组成:
| 组成部分 | 说明 |
| PE32 或 PE32+ 头 | 标准WINDOW PE 文件头,类似于 "公共对象文件格式"(Common Object File Format, COFF) 头。如果这个头使用 PE32 格式,则文件能在Windows 32 位或 64 位版本上运行。如果使用 PE32+ 格式,则只能在Windows 64 位版本上运行。这个头还包括其它信息。 |
| CLR 头 | 包含使这个模块成为一个托管模块的信息(可由CLR 和一些实用程序解释)。头中包含了需要的CLR 版本,一些标志(Flag),托管模块入口方法(Main 方法)的MethodDef 元数据标记(token),以及模块的元数据、资源、强名称、一些Flag以及其它不太重要的数据项的位置大小。 |
| 元数据 |
当局者迷how func;asdf asdfksdfasd fsadf
每个托管模块都包含元数据表。主要有两种类型的表:一种类型的表描述源代码中定义的类型与成员;另一种类型的表描述源代码中引用的类型与成员。 一般为描述其他对象而建立的对象都会加上“元”,元数据就是描述其他数据的数据。在.NET 中,其他数据指.NET 对象,引用到的对象及他们的关系。 |
| IL (中间语言) 代码 | 编译器编译时生成的代码。在运行时,CLR 将IL 编译成本地CPU 指令。(IL 代码有时称为托管代码) |
JIT(just-in-time)
执行一个方法时,必须将将IL 由JIT (just-in-time ,即时编译器)转换成本地CPU 指令。
分析书中的例子:

在Main方法执行之前,CLR会检测出Main的代码引用的所有类型。这将导致CLR分配一个内部数据结构,它用来管理对所用引用的类型的访问。 例如上图,Main方法引用了一Console类型,这导致CLR分配一个内部结构。在这个内部结构中,Console类型定义的每个方法都有一个对应的 记录项。每个记录项都容纳一个地址,根据此地址既可以找到方法的实现。对这个结构进行初始时,CLR将每个记录项都设置成(指向)包含在CLR内部的一个 未文档化的函数。我将这个函数成为JITCompiler。
Main首次调用WriteLine时,JITCompiler函数会被调用。JITCompiler函数负责将一个方法IL代码编译成本地 CPU指令。由于IL是“即时”(just in time)编译的,所以通常CLR的这个组件称为JITter或者JIT编译器。
JITCompiler函数被调用时,它知道要调用的是哪个方法,以及具体是什么类型定义了该方法。然后,JITCompiler会在定义程序集的元数据中查找被调用的方法的IL。接着,JITCompiler验证IL代码,并将IL代码编译成本地CPU指令。本地CPU指令被保存到一个动态分配的内存块中。然后,JITCompiler返回CLR为类型创建的内部数据结构,找到与被调用的方法对象的那一条记录,修改最初对 JITCompiler的引用,让它现在指向内存块中的地址。最后,JITCompiler函数跳转到内存块中的代码。
第二次调用WriteLine。这一次,由于对WriteLine的代码进行了验证和编译,所以直接执行内存块中的代码,完全跳过JITCompiler函数。
第二次调用WriteLine的情况 :

元数据
元数据是一个二进制数据块,由几个表构成。这些表分为三个类别:定义表(definiton talbe)、引用表(reference table)和清单表(mainfest table)。
常用的元数据定义表:
| 元数据定义表名称 | 说明 |
|---|---|
| ModuleDef | 总是包含一个用于标示模块的记录项 |
| TypeDef | 模块中定义的每个类型都在这个定义表中有一个对应的记录项。 |
| MethodDef | 模块中定义的每个方法都在这个定义表中有一个对应的记录项。 |
| FieldDef | 模块中定义的每个字段都在这个定义表中有一个对应的记录项 |
| ParamDef | 模块中定义的每个参数都在这个定义表中有一个对应的记录项 |
| PropertyDef | 模块中定义的每个属性都在这个定义表中有一个对应的记录项 |
| EventDef | 模块中定义的每个事件都在这个定义表中有一个对应的记录项 |
使用ILDasm.exe 查看TypeDef 元数据定义表:

常用的引用元数据表:
| 引用元数据表名称 | 说明 |
| AssemblyRef | 模块中引用的每个程序集在这个表中都有一个对应的记录项 |
| ModuleRef | 模块引用的每个类型可能是由别的PE模块实现的,所有那些模块在这个表都有一个记录项 |
| TypeRef | 模块引用的每个类型在这个表中都有一个对应的记录项 |
| MemberRef | 模块引用的每个成员都在这个表中有一个对应的记录项 |
使用ILDasm.exe 查看AssemblyRef 元数据引用表:

使用ILDasm.exe 查看TypeRef 元数据引用表:

清单元数据表:
| 清单元数据表名称 | 说明 |
| AssemblyDef | 如果该模块标示的是一个程序集,就在这个元数据表中包含单个记录项。该记录项列出了程序集名称(不含路径和扩展名)、版本(major,minor,build和revision)、语言文化(culture)、一些标志(flag)、哈希算法以及发布者的公钥。 |
| FileDef | 作为程序集一部分的每个PE文件和资源文件在这个表中都有一个对应的记录项。 |
| MainifestResourceDef | 作为程序集一部分的每个资源在这个表中都有一个对应的记录项 |
| ExportedTypesDef | 从程序集的所有PE模块中导出的每个public类型中在这个表中都有一个对应的记录项。 |
使用ILDasm.exe 查看AssemblyDef 清单元数据表

CLR 解析类型引用

编译这段代码并生成一个程序集,假定为Program.exe 。运行这个应用程序时,CLR 执行步骤为:
1:会加载并初始化它。
2:读取程序集的CLR 头,查找标识了应用程序入口的方法(Main)的MethodDefToken 。
3:检索MethodDef 元数据表,找到该方法的IL 代码在文件中的偏移量,把这些代码JIT(Just In Time)编译成本地(Native)代码。
当以下的IL 代码进行JIT 编译时,CLR 会检查参类型和成员的所有引用,并加载定义了它们的程序集(如果尚未加载)。


类型绑定过程如下:

CLR - 基础的更多相关文章
- 第一部分 CLR基础:第3章 共享程序集和强命名程序集
第一部分 CLR基础:第3章 共享程序集和强命名程序集
- Windbg CLR基础小测 《第六篇》
首先写一段代码如下: namespace ConsoleApplication3 { class Program { static void Main(string[] args) { Console ...
- 第一部分 CLR基础:第1章 CLR的执行模型
1.1将源代码编译成托管模块
- 01.由浅入深学习.NET CLR 基础系列之CLR 的执行模型
.Net 从代码生成到执行,这中间的一些列过程是一个有别于其他的新技术新概念,那么这是一个什么样的过程呢,有什么样的机制呢,清楚了这些基本的东西我们做.Net的东西方可心中有数.那么,CLR的执行模型 ...
- CLR基础之一---认识CLR [《CLR via C#》读书笔记]
<CLR via C#>读书笔记 什么是CLR CLR的基本概念 通用语言运行平台(Common Language Runtime,简称CLR)是微软为他们的.Net虚拟机所选用的名称.这 ...
- CLR基础与术语
CLR(Common Language Runtime):一个可由多种编程语言使用的"运行时". CLR的核心功能(内存管理,程序集加载,安全性,异常处理,线程同步等)可由面向CL ...
- CLR基础
一.各个语言的长处 ①非托管C/C++可对系统进行低级控制.可完全按照自己的想法管理内存,必要时方便地创建线程②使用Microsoft Visual Basic 6.0可以快速生成UI应用程序,并可以 ...
- CLR基础,CLR运行过程,使用dos命令创建、编译、运行C#文件,查看IL代码
CLR是Common Language Runtime的缩写,是.NET程序集或可执行程序运行的一个虚拟环境.CLR用于管理托管代码,但是它本身是由非托管代码编写的,并不是一个包含了托管代码的程序集, ...
- 重温CLR(一)CLR基础
如果一个C#developer,对CLR没有了解,那就只能是入门级别.未来.NET CORE是趋势,但是.NET CORE 也是基于CoreCLR的,而CLR和CoreCLR其实差别不大,从runti ...
随机推荐
- 国外60个专业3D模型网站
原始链接:http://blog.sina.com.cn/s/blog_4ba3c7950100jxkh.html Today, 3D models are used in a wide variet ...
- Laravel5.6安裝:Warning: require(../vendor/autoload.php): failed to open stream: No such file or directory
在phpstudy下使用composer+laravel安装器的方式安装了Laravel,但是访问的时候报错: Warning: require(D:\phpstudy\WWW\public\mybl ...
- input type=”file“ change事件只执行一次的问题
js解决办法 HTML:<input id="file",type="file" onchange="upload()" /> ...
- 记一次vip视频破解过程(爱奇艺 芒果 腾讯 优酷 )
1. 在爱奇艺或者优酷中拿到视频的url地址.此时拿到的是加密地址(也可以直接在牛巴巴里面搜名字然后开f12跟踪路由) 2.进入牛巴巴vip视频解析网站.粘贴拿到的url.点击解析 3.f12在net ...
- Python笔记7----Pandas中变长字典Series
1.Series概念 类似一维数组的对象,由数据和索引组成 2.Series创建 用Series()函数创建,0,1,2为series结构自带的索引. 可以自己指定索引值,用index,也可以直接用字 ...
- 容器化haproxy+keepalived
# 拉取haproxy镜像 docker pull haproxy:1.7.8-alpine mkdir /etc/haproxy cat >/etc/haproxy/haproxy.cfg&l ...
- C语言提高 (7) 第七天 回调函数 预处理函数DEBUG 动态链接库
链表就是一个结构体 指针指向自身结构体类型 双向链表插入的时候 先改变自身 再改变两边 双向链表删除的时候 先改变两边 再改变自己 逆序一个单向链表 回调函数 指向函数的指针 4链表的遍历回调用法 / ...
- AOJ 2224 Save your cats( 最小生成树 )
链接:传送门 题意:有个女巫把猫全部抓走放在一个由 n 个木桩(xi,yi),m 个篱笆(起点终点木桩的编号)围成的法术领域内,我们必须用圣水才能将篱笆打开,然而圣水非常贵,所以我们尽量想降低花费来解 ...
- 用户登录记住用户名导致表单自动填充bug解决方法
最近做项目出现了一个极其讨厌的bug:在用户登录网站时,浏览器会自动提示是否记住密码,当选择记住密码时,正常浏览网页,会发现有那么几个input输入框会自动填充用户名,非常讨厌, 于是就觉得挺简单的一 ...
- 从零開始写游戏引擎(一) - project创建以及文件夹设置还有版本号控制
一句话提要 好的開始等于成功了一半. 创建文件夹结构 project文件夹下最好分为以下几个文件夹 Docs - 开发文档,设计文档 Assets - 角色,动作,模型和音效等 Source - 代码 ...