CIL之——初识CIL
通用中间语言(Common Intermediate Language,简称CIL)(亦被称作MSIL或IL)是一种属于通用语言基础架构和.NET框架的低阶(lowest-level)的人类可读的编程语言,它是一种代码指令集。CIL可以在任何支持CLI(Common Language Infrastructure,通用语言基础架构)的环境中运行,.NET是微软对CLI的实现,Mono是Xamarin对CLI的又一实现,所以CIL能在.NET运行时以及Mono运行时中运行,跟具体的平台或者CPU无关,这样就无需为不同的平台部署不同的内容了。
如果想让一份代码在不同的平台中运行,只需要把代码的编译分为两部分即可:
1、把源代码编译成CIL的预编译过程(其实之后CIL还会被编译成一种位元码,生成一个CLI Assembly)
2、运行时把CIL(其实是CLI Assembly)编译成本地指令的即时编译过程
初始CIL代码
C#代码:
namespace ConsoleTest
{class Program{// Methodsprivate static void Main(string[] args){Console.WriteLine("Hello World");Console.ReadKey();}}
}
CIL代码:
.class private auto ansi beforefieldinit ConsoleTest.Programextends [mscorlib]System.Object
{.method public hidebysig specialname rtspecialname instance void .ctor() cil managed{// 代码大小 7 (0x7).maxstack 8IL_0000: ldarg.0IL_0001: call instance void [mscorlib]System.Object::.ctor()IL_0006: ret} // end of method Program::.ctor.method private hidebysig static void Main(string[] args) cil managed{.entrypoint// 代码大小 19 (0x13).maxstack 8IL_0000: nopIL_0001: ldstr "Hello World"IL_0006: call void [mscorlib]System.Console::WriteLine(string)IL_000b: nopIL_000c: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()IL_0011: popIL_0012: ret} // end of method Program::Main} // end of class ConsoleTest.Program
代码虽然简单,但也足够说明一些问题,下面让我们了解一下CIL代码:
1、以”.”一个点号开头的,例如上面这份代码中的.class、.method以及本例中未出现的.namespace,我们称之为CIL指令,用于描述.NET程序集总体结构的标记。为啥需要它呢?因为你总得告诉编译器你处理的是啥吧。
2、CIL代码中还出现了private、public,我们称之为CIL特性(attribute)。通过CIL指令并不能完全说明.NET成员和类,CIL特性的作用就是针对CIL指令进行补充说明成员或者类的特性。市面上常见的还有:extends、implements等等。
3、每一行CIL代码都使用了CIL操作码,例如:ldarg.0、ldstr、call、nop、ret等。
然后比较C#代码与对应的CIL 代码的不同之处:
1、C#代码Program类中没有构造方法,CIL代码中却有,说明编译器自动为类生成了无参构造方法。
2、为什么程序运行后总是执行Main()方法呢?因为Main()方法中设置了程序入口点(即.entrypoint),并不是因为它的名字是Main就得先执行……
3、经过对比发现:CIL代码比C#代码更接近程序的本质
基于堆栈
CIL是基于堆栈的,也就是说CIL 的VM(mono运行时)是一个栈式机。这就意味着数据是先推入堆栈,然后通过堆栈来操作的,而不是通过CPU寄存器来操作,这更加验证了其和具体CPU架构没有关系。
CIL之所以是基于堆栈而非CPU的一个原因是相比较于CPU的寄存器,操作堆栈实在太简单了,只需要简单的压栈和弹出,这对于虚拟机的实现来说再合适不过了。如果想要更具体地了解CIL基于堆栈这一点,各位可以去看一下堆栈这方面的内容,这里就不拓展了。
面向对象
就像C#一样,CIL同样是面向对象的。这就意味着在CIL中你可以创建对象,调用对象的方法,访问对象的成员。而这里需要注意的就是对方法的调用,调用静态方法和调用实例方法是不一样的。
- 静态方法:ldarg.0没有被占用,所以参数从ldarg.0开始
- 实例方法:ldarg.0被this占用,所以参数从ldarg.1开始
举例说明,假设类Guo中有一个静态方法和一个实例方法,代码如下:
namespace ConsoleTest
{public class Guo{public static int Subtract(int num1, int num2){return num1 - num2;}public void Show(string message){Console.WriteLine(message);}}
}
a. 静态方法Subtract的CIL代码如下:
.method public hidebysig static int32 Subtract(int32 num1,int32 num2) cil managed
{// 代码大小 9 (0x9).maxstack 2.locals init ([0] int32 CS$1$0000)//初始化局部变量。由于本方法的返回值为int型,所以声明了一个int32类型的局部变量,用以保存返回值。IL_0000: nopIL_0001: ldarg.0 //将索引为0的参数加载到计算堆栈上IL_0002: ldarg.1 //将索引为1的参数加载到计算堆栈上IL_0003: sub //计算IL_0004: stloc.0 //弹出当前计算堆栈顶弹部的值并将其存储到索引为0的局部变量中IL_0005: br.s IL_0007IL_0007: ldloc.0 //将索引为0的局部变量加载到计算堆栈上IL_0008: ret //弹出当前计算堆栈顶弹部的值并返回
} // end of method Guo::Subtract
我们可以直接通过类名来调用这个静态方法:
Guo.Subtract(5,6);
对应的CIL代码为:
.method private hidebysig static void Main(string[] args) cil managed
{.entrypoint// 代码大小 10 (0xa).maxstack 8IL_0000: nopIL_0001: ldc.i4.5IL_0002: ldc.i4.6IL_0003: call int32 ConsoleTest.Guo::Subtract(int32,int32)IL_0008: popIL_0009: ret
} // end of method Program::Main
可见CIL直接call了类ConsoleTest.Guo的Subtract方法,不需要加载类ConsoleTest.Guo的实例。
b. 实例方法Show的CIL代码如下
.method public hidebysig instance void Show(string message) cil managed
{// 代码大小 9 (0x9).maxstack 8IL_0000: nopIL_0001: ldarg.1 //将索引为1的参数加载到计算堆栈上,静态方法中第一个参数的索引是0IL_0002: call void [mscorlib]System.Console::WriteLine(string)IL_0007: nopIL_0008: ret
} // end of method Guo::Show
实例方法不能直接通过类名来调用,需要通过类的实例来调用:
Guo objGuo = new Guo();
objGuo.Show("Hello");
对应的CIL代码为:
.method private hidebysig static void Main(string[] args) cil managed
{.entrypoint// 代码大小 20 (0x14).maxstack 2.locals init ([0] class ConsoleTest.Guo objGuo)//声明一个ConsoleTest.Guo类型的局部变量,用以保存类的对象IL_0000: nopIL_0001: newobj instance void ConsoleTest.Guo::.ctor()IL_0006: stloc.0IL_0007: ldloc.0IL_0008: ldstr "Hello"IL_000d: callvirt instance void ConsoleTest.Guo::Show(string)IL_0012: nopIL_0013: ret
} // end of method Program::Main
CIL调用类ConsoleTest.Guo的Show方法时,需要先把类ConsoleTest.Guo的实例加载到计算堆栈(ldloc.0),然后再callvirt调用。由此也验证了:实例方法不能直接通过类名来调用,需要通过类的实例来调用。
CIL之——初识CIL相关推荐
- 由浅入深CIL系列:2.CIL的基本构成+CIL操作码速记表+CIL操作码大全速查
一.CIL的基本构成 CIL由CIL指令(directive).CIL特性(attribute).CIL操作码(opcode)组成. CIL指令 CIL指令是用于描述.NET程序 ...
- 由浅入深CIL系列【目录索引】+ PostSharp AOP编程【目录索引】
CIL简介:CIL(Common Intermediate Language)中文名为通用中间语言,注意它曾经被称为微软中间语言或MSIL,它是一种类似于JAVA字节码的语言.在微软语言平台中,不管程 ...
- Unity3D为何能跨平台?聊聊CIL(MSIL)
前言 其实小匹夫在U3D的开发中一直对U3D的跨平台能力很好奇.到底是什么原理使得U3D可以跨平台呢?后来发现了Mono的作用,并进一步了解到了CIL的存在.所以,作为一个对Unity3D跨平台能力感 ...
- 从游戏脚本语言说起,剖析Mono所搭建的脚本基础
0x00 前言 在日常的工作中,我偶尔能遇到这样的问题:"为何游戏脚本在现在的游戏开发中变得不可或缺?".那么这周我就写篇文章从游戏脚本聊起,分析一下游戏脚本因何出现,而mono又 ...
- Understanding JVM Internals---不得不转载呀
http://www.cubrid.org/blog/dev-platform/understanding-jvm-internals/ http://architects.dzone.com/art ...
- 魅力 .NET:从 Mono、.NET Core 说起
转自:http://kb.cnblogs.com/page/514268/ 前段时间,被问了这样一个问题:.NET 应用程序是怎么运行的? 当时大概愣了好久,好像也没说出个所以然,得到的回复是:这是 ...
- Unity3d--跨平台(一)
转自:https://www.cnblogs.com/murongxiaopifu/p/4211964.html 前言: 其实小匹夫在U3D的开发中一直对U3D的跨平台能力很好奇.到底是什么原理使得U ...
- 缓冲区溢出还是问题吗?C++/CLI安全编码
C++/CLI是对C++的一个扩展,其对所有类型,包括标准C++类,都添加了对属性.事件.垃圾回收.及泛型的支持. Visual C++ 2005扩展了对使用C++/CLI(通用语言基础结构)开发运行 ...
- sprd camera 帧率设置_UnityPlayerSetting-Android 打包设置介绍
Resolution And Presentation Start in fullscreen mode 以全屏模式启动 在启用的情况下,在第一次启动时隐藏导航栏(拦窗),如果未设置,则在第一次启动时 ...
最新文章
- spring WebServiceTemplate 调用 axis1.4 发布的webservice
- js、jquery相关的操作
- 《ArcGIS Runtime SDK for Android开发笔记》——(2)、Android Studio基本配置与使用
- centos安装g++
- 深入Python(2): __init__.py 用法
- python面向对象编程的三大特性_Python面向对象总结及类与正则表达式详解
- Django之model补充:一对多、跨表操作
- 那些年踩过的坑之:first-child伪类选择器
- Java中NLP的学习
- C#复习笔记(2)--C#1所搭建的核心基础
- 机器学习模型之集成算法
- web页面移动端键盘弹出后对页面布局的影响
- CUDA的旋转R ROI Align的OPENCL实现1(原理理解)
- 2022年草根互联网圈较流行的副业汇总
- 叶俊|从人类基因本能谈到赞美的力量|麻辣总裁幽默SHOW嗨翻全场
- 笔记本cmd重启计算机的代码,怎么让电脑不断重启(用cmd实现)
- Python常用开发软件有哪些?
- 阿里技术风险与效能部负责人张瓅玶:阿里集团深度用云实践
- Python中flask_sqlalchemy的使用
- 视频H.263与H.264的比较