四、CLR执行程序集中代码和IL代码简介

三、加载公共语言运行时中介绍了在安装了.Net Framework中加载公共语言运行时,公共语言运行时加载程序集的过程.以及通过vs stdio设置源码编译的目标平台的过程.

本问主要介绍公共语言加载完程序集之后,执行程序集中的代码的过程.

一、IL中间语言

1、IL简介

一、源代码-面向CLR的编译器-托管模块-(元数据&IL代码)中介绍了C#源代码通过C#编译器生成的最终产物是托管模块,而托管模块是由IL中间语言和元数据组成,IL语言是比大多数机器语言都要高级的语言,IL有以下功能:

(1)、能访问和操作对象类型

(2)、提供了指令创建和初始化对象

(3)、调用对象上的虚方法和操作数组

(4)、提供了抛出和捕捉异常的指令实现错误处理

......等等

因此,可将IL视为一种面向对象的机器语言.

2、IL通识

(1)、我们一般通过C#或者F#或者Visual Basic来编程,然后编译器将它们编译成IL,然后IL和其他机器语言一样,也可以使用汇编语言来编写,MS提供了ILAsm.exe的IL汇编器和ILDasm.exe的反汇编器.

(2)、通常高级语言只提供CLR全部功能的一个子集,然而IL汇编语言允许开发人员方法CLR的全部功能,如果你选择的编程语言隐藏了一个你迫切需要的功能,那么你可以使用IL汇编语言来实现,或者使用另一种编程语言来实现

3、CLR执行一个方法时发生的事情

(1)、第一次执行

(2)、第二次执行

 如果Main方法第二次调用Console的WriteLine方法,会完全跳过JITComliler函数,因为第一次已经执行和初始化过了,会执行执行内存块中的代码,执行完毕有返回值,则返回到Main(),没有返回值,则跳转带Main方法,进行下一步操作.

注:方法只有在第一次运行时会有JIT进行IL验证和IL编译成本机代码造成的性能损失,以后对该方法的调用都已本机代码的形式全速运行,无需验证IL代码并把它编译成本地代码.

4、CLR执行方法时的IL和验证

(1)、IL基于栈

它的所有指令要将操作数压入一个执行栈,并从栈中弹出(pop)结果。由于IL没有提供操作寄存器的指令,所有人们很容易的创建新的语言和编译器,生成面向CLR的代码.

(2)、IL指令"无类型"

例:IL提供了Add指令将压入栈的最后的两个操作数加到一起.add指令不分32位和64位版本.当add指令执行时,它判断栈中的操作数的类型,并执行恰当的操作.

(3)、IL指令最大的优势

IL最大的优势并不是对底层的抽象,而是应用程序的健壮性和安全性.将IL编译成本机CPU指令时,CLR会检查验证高级IL代码,确定代码所做的一切操作都是安全的.

例如:会核实调用的每个方法都有正确数量的参数,传给每个方法的每个参数都有正确的类型,每个方法的返回值都得到了正确的使用,每个方法都有一个返回语句.

注:托管模块的元数据包含验证过程要用到的所有方法及类型信息.

(4)、IL验证对进程产生的影响

windows的每个进程都有自己的虚拟地址空间,独立空间存在的是因为不能简单的信任一个应用程序的代码。应用程序完全可能读写无效的内存地址。将每个Windows进程都放到独立的地址空间,将获得健壮性和稳定性,一个进程干扰不到另一个进程.

通过验证托管代码,可以确保代码不会不正确地访问内存,不会干扰另一个应用程序的代码.这样就可以放心地将多个托管应用程序放到同一个Windows虚拟地址空间运行。

注:由于windows进程需要大量的操作系统资源,所以进程数量太多,会损害性能并制约可用的资源。用一个进程运行多个应用程序,减少进程,增强性能,减少所需的资源,健壮性没有丝毫下降,这是托管代码的优势之一.

CLR提供了在一个操作系统进程中执行多个托管应用程序的能力,每个应用程序都在一个AppDomain中执行,每个托管Exe文件默认都在它自己的独立地址空间中运行,这个地址空间已有一个AppDomain.

注:IIS和SQL Server可实现在一个进程中运行多个AppDomain.

5、CLR执行不安全的代码

C#编译器默认生成安全的代码,代码的安全性可以验证,然而C#编译器也允许开发人员写不安全的代码,不安全的代码允许直接操作内存,并可操作这些地址处的字节。这是一个很强大的功能,不过一般是在提升一个对效率要求极高的算法的时候使用。

然而,使用不安全的代码存在重大风险,这种代码可能会破坏数据结构,危害安全性,甚至造成新的安全漏洞,所以,C#编译器要求不安全的代码都使用unsafe关键字标记.

注:当JIT编译器编译一个unsafe方法时,该程序集必须有System.Security.Permissions.SecurityPermission权限.且System.Security.Permissions.SecurityPermissionFlagd的SkipVerification的标志是否设置,如果设置了,JIT编译器会便宜unsafe的代码.

MS提供了PEVerify.exe的程序,用它检查一个程序集的所有方法,并报告其中不安全代码的方法.

6、实现IL代码验证的技术

JIT验证IL代码时.必须要访问所有以来的程序集中包含的元数据.例如:当PEVerify检查程序集时,它必须能够定位并加载应用的所有的程序集.

CLR是采用和平时执行程序集时一样的绑定和探测规则来定位程序集.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏企鹅号快讯

Python的进程

进程 说明:本文是基于Py2.X环境, Python实现多进程的方式主要有两种:一种方法是使用os模块中的fork方法; 另一种是使用multiprocessi...

23910
来自专栏郭耀华‘s Blog

Python 中的 if __name__ == '__main__' 该如何理解

1103
来自专栏令仔很忙

Hibernate从入门到放弃(三)----持久化对象

当对象刚创建,和Session没有发生任何关系时,当程序运行完成就立刻消失,被称为瞬时态。瞬态对象不会被持久化到数据库中,也不会被赋予持久化标识,如果程序中失...

1211
来自专栏程序员的知识天地

Python使用os模块、Try语句、pathlib模块判断文件是否存在

通常在读写文件之前,需要判断文件或目录是否存在,不然某些处理方法可能会使程序出错。所以最好在做任何操作之前,先判断文件是否存在。

1462
来自专栏运维技术迷

Python:获取目录下指定后缀的文件

os.walk()和os.listdir()两种方法,获取指定文件夹下的文件名. 获取当前目录下指定后缀的文件 #!/usr/bin/env python #c...

5859
来自专栏AILearning

多线程的基础学习

进程:是一个正在执行中的程序, 每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。 线程:是进程中的一个独立的控制单元, 线程在控制中进...

1847
来自专栏大内老A

ASP.NET Core管道深度剖析(4):管道是如何建立起来的?

在《管道是如何处理HTTP请求的?》中,我们对ASP.NET Core的请求处理管道的构成以及它对请求的处理流程进行了详细介绍,接下来我们需要了解的是这样一个管...

1906
来自专栏林冠宏的技术文章

Golang 的 协程调度机制 与 GOMAXPROCS 性能调优

Golang 简称 Go,Go 的协程(goroutine) 和我们常见的线程(Thread)一样,拥有其调度器。

4011
来自专栏java一日一条

深入分析Java线程中断机制

在平时的开发过程中,相信都会使用到多线程,在使用多线程时,大家也会遇到各种各样的问题,今天我们就来说说一个多线程的问题——线程中断。在java中启动线程非常容易...

792
来自专栏腾讯移动品质中心TMQ的专栏

从Java乱码谈起

在实际项目开发中,特别是涉及到中文输入输出的时候,大家肯定都被各种乱码问题坑过。如果遇到复杂的系统,为了乱码问题折腾几天也不是不可能。

4606

扫码关注云+社区

领取腾讯云代金券