当前位置:网站首页>CLR via C# 第一章 CLR的执行模型

CLR via C# 第一章 CLR的执行模型

2022-08-11 05:31:00 canon_卡农

1.1、将源代码编译成托管模块

1.CLR(Common Language Runtime)面向多种编程语言,提供内存管理、程序集加载、安全性、异常处理和线程安全等核心功能。

2.过程:源代码文件–> 编译器检查语法和分析源代码–>托管模块(managed module)

3.托管模块组成
(1) PE32或PE32+头——Windows PE文件头,其中PE32+只能在WIN64上运行。
标识了文件类型(GUI、CUI、DLL)
包含一个时间标记(文件的生成时间)
如果是包含本机(native)CPU代码的模块,这个头含与本机CPU代码有关的信息

(2) CLR头
包含要求的CLR版本
一些flag标志
托管模块Main方法的MethodDef元数据token
模块的元数据、资源、强名称、一些标志以及一些不重要的数据项的位置/大小

(3) 元数据——数据表的集合
源代码中定义的类型和成员的元数据表、以及引用的类型元数据表

(4) IL代码——编译器编译源代码生成的代码
在运行时,CLR(需要安装.NET Framework)将IL编译成本机CPU指令

特殊:Microsoft的C++编译器默认生成包含 native 的exe/dll 文件,可以通过指定/CLR命令行开关生成包含托管代码的模块。

1.2、将托管模块合并成程序集

通过AL.exe链接
Assembly:重用、安全性、版本控制的最小单元。程序集是自描述的,在程序集的模块中包含了引用的程序集的相关信息(包括版本号),不需要在注册表或Active Directory Domain Services中保存额外信息。所以与非托管组件代码相比,程序集更容易部署。

1.3、加载公共语言运行时

检查系统目录中是否存在 mscoree.dll 以确定安装了.NET Framework:
在这里插入图片描述
Windows通过检查exe文件头,决定创建32位进程还是64位进程,随后在进程地址空间加载相应版本的MSCorEE.dll,然后进程的主线程调用MSCorEE.dll中定义的一个方法初始化CLR,加载EXE程序集,最后调用其入口方法(Main),托管程序启动并运行。

如果是非托管引用程序调用 LoadLibrary 加载托管程序集,Windows会自动加载并初始化CLR以处理程序集中的代码。这个时候进程已经启动并运行了,可能会限制程序集的可用性。

1.4、执行程序集的代码

托管程序集包含元数据和 IL,IL是面向对象的机器语言。Microsoft提供了IL汇编器:ILAsm.exe
和IL反汇编器:ILDasm.exe

CLR是如何执行程序集的代码的?
在Main方法执行之前,CLR会检测出Main的代码引用的所有类型。这导致CLR分配一个内部数据结构来管理对引用类型的访问。
在这里插入图片描述
如图,Main方法引用了 Console 类,导致CLR分配一个内部结构。在这个数据结构中,Console类定义的每个方法都有一个对应的entry,每个entry 都含有一个地址,根据此地址可以找到方法的实现。对这个结构初始化时,CLR将每个 entry 设置成 指向包含在CLR内部的一个未编档函数(称为JITCompliler)
Main函数首次调用WriteLine时,JITCompiler函数会被调用,此时,JIT知道它要定义的是哪个类型定义的哪个方法。然后,JIT会在定义该类型的程序集的元数据中查找被调用方法的IL。通过验证(verification)后,JIT将方法的IL代码编译成本机CPU指令(x86、x64、ARM等)并保存到动态分配的内存块中。然后,JIT回到CLR为类型创建的内部数据结构中,修改entry 对JITCompliler的引用,使其指向内存块。最后,JIT跳转执行内存块中的代码,执行完毕后回到Main函数,继续执行Main函数。第二次执行该方法时则会跳过JIT直接执行本机代码。

注意:CLR的JIT编译器会对本机代码进行优化,受 /optimize和 /debug 两个C#编译器开关影响。

原网站

版权声明
本文为[canon_卡农]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_41044598/article/details/124480075