微软中间语言—MSIL(转载)
在.Net框架中,公共语言基础结构使用公共语言规范来绑定不同的语言。通过要求不同的语言至少要实现公共类型系统(CTS)包含在公共语言规范中的部分,公共语言基础结构允许不同的语言使用.Net框架。因此在.Net框架中,所有的语言(C#,VB.Net,Effil.Net等)最后都被转换为了一种通用语言:微软中间语言(MSIL)。
MSIL是将.Net代码转化为机器语言的一个中间过程。它是一种介于高级语言和基于Intel的汇编语言的伪汇编语言。当用户编译一个.Net程序时,编译器将源代码翻译成一组可以有效地转换为本机代码且独立于CPU 的指令。当执行这些指令时,实时(JIT)编译器将它们转化为CPU特定的代码。由于公共语言运行库支持多种实时编译器,因此同一段MSIL代码可以被不同的编译器实时编译并运行在不同的结构上。从理论上来说,MSIL将消除多年以来业界中不同语言之间的纷争。在.Net的世界中可能出现下面的情况:一部分代码可以用Effil实现,另一部分代码使用C#或VB完成的,但是最后这些代码都将被转换为中间语言。这给程序员提供了极大的灵活性,程序员可以选择自己熟悉的语言,并且再也不用为学习不断推出的新语言而烦恼了。
解密微软中间语言的系列文章将通过一些简单易懂的方式来揭示中间语言的复杂原理。这些原理通过详细的例子来阐述。在一些例子中同时给出了源代码和中间代码,通过比较源代码和中间代码,我们可以更好地理解编译器的局限性,指导我们编写出更好更快的代码。
微软中间语言概述
1.用中间语言编写的一个简单程序
让我们从经典的Hello World例子开始。首先在一个文本编辑器中输入以下的代码,并保存为HelloWorld.il:
.assembly HelloWorldIL {} .method static void HelloWorld() { .entrypoint ldstr "Hello World." call void [mscorlib]System.Console::WriteLine(class System.String) ret } |
在一个中间语言程序中,如果某一行以“.”开始,则代表这是一个传输给汇编工具的指令,该指令要求汇编工具执行某些操作,例如生成一个函数或类。而没有以“.”开始的行是中间语言的代码。在中间语言中方法通过汇编命令method来定义,汇编命令后跟方法的返回值、名称和参数。方法体被包含在{}中。例子中的ret代表该方法的结束。
一个中间语言文件可以包含很多函数,汇编工具没有办法分辨应该首先执行哪一个方法。在诸如C#或VB这一类高级语言中,程序的入口方法通常都有特定的名称,例如在C#中的public static void Main()。这就是上面的汇编工具发出错误提示的原因。在中间语言中,第一个被执行的方法被称为入口函数(EntryPoint Function)。为了告诉汇编工具HelloWorld是入口函数,我们需要在代码中增加一条汇编命令entrypoint,该命令可以放在方法体中的任何位置。需要注意的是在一个程序集中只能有一个入口函数。
中间语言代码通常被编译成一个模块,该模块隶属于一个程序集。在.Net中模块和程序集的概念非常重要,因此开发人员需要很清楚地了解它们。在后面的文章中我们将详细讨论.Net程序的结构。通过在代码中加入assembly命令,可以告诉汇编工具中间代码隶属于那个程序集。assembly命令的格式如下:
.assembly <程序集名称> {} |
需要注意在method命令后加入了static关键字,这是因为每个入口函数必须是静态的,例如在C#中我们将Main方法定义为public static void Main()。
接下来我们需要调用WriteLine方法将HelloWorld字符串输出到屏幕。通过使用call指令(Instruction)我们可以达到这个目的。指令的格式如下:
call <return type> <namespace>.<class name>::<method name> |
这里我们可以看到当调用一个方法时,中间语言和其他的编程语言有很大的区别。在中间语言中,如果需要调用一个方法,需要指定方法的全名,包括他的名称域(namespace)、类名、返回值类型和参数的数据类型。这样就保证了汇编工具能够找到正确的方法。
在调用WriteLine方法时需要一个字符串参数。所有传递给方法或函数的参数都被保存在内存的堆栈中。在中间语言中有一个指令ldstr可以从堆栈中加载一个字符串。(堆栈是内存中的一块区域,它被用于将参数传输给方法,在后面我们会详细讨论堆栈的问题)。所有的方法都从堆栈中获取它们的参数,因此ldstr指令是必不可少的。ldstr指令的格式如下所示:
ldstr <parameter string> |
我们可以用ILAsm.exe来编译这个程序。在运行ILAsm.exe之前,首先需要确认一下该程序已经包含在了Windows操作系统的Path环境变量中。ILAsm.exe 可在下面的路径中找到:
%windir%/Microsoft.NET/Framework/v1.0.xxxx |
其中xxxx是正在使用的.NET框架的内部版本号。例如我使用的版本号是3705,则应该如下设置Path环境变量:
Set Path = %Path%;c:/Windows/Microsoft.NET/Framework/v1.0.3705 |
然后运行cmd.exe(开始->运行->输入cmd->按下确认键)。在弹出的命令窗口中输入:
J:/Testcode>ilasm HelloWorld.il |
汇编代码后运行程序就可以看到Hello World.的输出。
通过上面的例子,我们了解了中间语言的程序结构,一些命令和指令。同时需要提醒大家的是中间语言是区分大小写的。
2.改进的HelloWorld例子
在.Net中的所有语言都是面向对象的语言,但是上面的HelloWorld例子是一个结构化的例子。下面让我们来看一下如何将它转化为面向对象的代码。在面向对象的编程中,我们将操作定义在类中。为了将上面的HelloWorld例子转化为面向对象的代码,可以使用class命令:
.class HelloWorld { } |
class命令后紧跟的是类的名称。类的名称在中间语言中是可选的。同时我们还需要为该指令添加一些属性,例如存取控制类在内存中的布局和互用性等。这样代码就变成了:
.assembly HelloWorldIL {} .class public auto ansi HelloWorld extends [mscorlib]System.Object { .method public hidebysig static void HelloWorld() cil managed { .entrypoint ldstr "Hello World." call void [mscorlib]System.Console::WriteLine(class System.String) ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } } |
在代码中用到了三个属性:
· public:public是访问控制属性,它表明了对于访问该类的成员没有限制。
· auto:auto属性表明了当类被加载到内存中时,在内存中的布局是由公共运行库而不是程序决定的。
· ansi:指定ansi属性是为了在没有被管理和被管理的代码之间实现无缝的转化。在.Net中,那些不可直接应用在公共语言基础设施之上的代码被称为没有被管理的代码,例如C、C++和VB6的代码。我们需要一个属性来处理被管理的代码和没有被管理的代码之间的互用性。在被管理的代码中,字符串用双字节的Unicode字符表示,而在被管理的代码中,字符串有可能用单字节的ANSI字符表示。指定了ansi属性就可以在不同的代码间转化字符串了。
我们知道在.Net框架中,所有的类都直接或间接地继承了System.Object类。在代码中我们明确指定了HelloWorld继承了System.Object。
在HelloWorld方法中加入了public、hidebysig、cil managed属性,下面是对这些属性的解释:
· public:在C#或VB.Net中,当我们定义一个方法时,需要指定方法的访问修饰符。访问修饰符可以是public、protected、internal或private 。
· hidebysig:一个类可以继承其他的类,hidebysig属性保证当前类中的方法在作为父类时不会被子类继承。例如如果HelloWorldChild类继承了HelloWorld类,在HelloWorldChild中不会看到HelloWorld方法。
· cil managed:该属性将在后面讨论。
在高级语言中(C#,VB.Net等),每个类必须有构造函数,而且构造函数的第一行需要调用基类的构造函数。如果类中没有构造函数,基类的构造函数将被自动调用。通常这是由编译器自动完成的,现在我们要在的代码中加入构造函数,该构造函数通过.ctor命令调用基类的构造函数。
小结
本文我们从经典的Hello World例子开始,通过实例了解了微软中间语言的基本语法规则以及中间语言与其他开发语言的关系。在下一篇文章中,我们将在此基础上,运用实例程序讲述.net应用程序的格式和结构等内容。
微软中间语言—MSIL(转载)相关推荐
- [转帖]解密微软中间语言MSIL之调试程序(1)
没有程序员敢保证没有经过调试的代码绝对没有错误,无论他/她智商多么高,开发出来的代码总是或多或少带有一些错误(当然是无意的:-)).这些错误可能是简单的语法错误或者复杂的逻辑错误.因此和其他语言一样, ...
- 开放源码的.NET 反编译工具 .NET IL调试工具 学习微软中间语言(MSIL)的绝佳工具 Dotnet IL Editor 推荐...
Dotnet IL Editor是一款.NET平台反编译工具,可以反编译.NET程序集文件为IL代码,并且可以执行,调试反编译后生成的IL代码.它的设计出发点比较直观,新建一个项目,添加程序集文件,设 ...
- 解密微软中间语言:MSIL
在.Net框架中,公共语言基础结构使用公共语言规范来绑定不同的语言.通过要求不同的语言至少要实现公共类型系统(CTS)包含在公共语言规范中的部分,公共语言基础结构允许不同的语言使用.Net框架.因此在 ...
- MSIL:微软中间语言——.Net语言无关性
MSIL是一种通用的中间语言,类似于现在国际使用的英语,实现语言无关性.各编程语言,如C#.Javad,通过编译器翻译成MSIL. MSIL是将.NET代码转化为机器语言的一个中间过程.它是一种介于高 ...
- 【翻译】MSIL 教程(一)
在网上发现了一个非常好的MSIL教程,可惜是英文版的,于是就翻译了一下,与大家共享, 原文http://www.codeguru.com/Csharp/.NET/net_general/il/arti ...
- MSIL 教程(一)
在网上发现了一个非常好的MSIL教程,可惜是英文版的,于是就翻译了一下,与大家共享, 原文http://www.codeguru.com/Csharp/.NET/net_general/il/arti ...
- MSIL(0):简介
Microsoft Intermediate Language (MSIL)微软中间语言 MSIL是将.NET代码转化为机器语言的一个中间过程.它是一种介于高级语言和基于Intel的汇编语言的伪汇编语 ...
- MSIL解析一(转)
转自:http://www.cnblogs.com/Yahong111/archive/2007/08/15/857140.html 在网上发现了一个非常好的MSIL教程,可惜是英文版的,于是就翻译了 ...
- 深入浅出.NET泛型编程(1)
深入浅出.NET泛型编程(1) 使用泛型集合 .NET 2.0的System.Collections.Generics 命名空间包含了泛型集合定义.各种不同的集合/容器类都被"参数化&quo ...
最新文章
- PYTHON自动化Day12-unittest自动注册登录
- Python基础day03【字符串(定义、输入输出、常用方法)、列表(定义、基本使用、增删改查、嵌套)、元组】
- 更轻易地实现 Jwt Token
- wireshark过滤使用
- 安装Bootstrap3源码版本
- 微信3.3.0 for Mac全新发布:新增视频号 可搜索微信号添加朋友
- 《跑跑卡丁车》国内运营商裁员超30%
- OpenAnolis社区致Linux开发者的一封信
- 用数据库表填充下拉列表框
- 解决黑苹果(bigsur)ALC255声卡声音发虚问题
- 汉王手写板linux驱动下载,汉王笔手写板驱动程序
- 解决Nextcloud新建用户默认语言是英文且默认地区是美国的方法
- 搭建个人网站(免备案)
- IC卡和ID卡初步了解
- 转载tangl_99的Servlet 实现文件上传下载--自己的一点心得
- allegro设置区域规则
- 常见的设计模式和应用场景
- GNU/Linux 初學之旅
- AD学习笔记(一)基础认识
- Quartz配置资源介绍
热门文章
- 错误	C4996	‘stricmp‘: The POSIX name for this item is deprecated. Instead,use the ISO C and C++解决方案
- 3d卷积和2d卷积1d卷积运算-CNN卷积核与通道讲解
- 尘缘如梦_转载网友_天还是那么蓝
- Python中私有变量和私有方法芳
- [PHP]读取CSV文件
- 传真服务器系统的架设方案
- CAKEPHP 快速入门
- 云桌面是什么意思?与堡垒机有什么区别?
- qq javax.mail.authenticationfailedexception
- 本地部署docker实践