IL是什么?
IL是Intermediate Language的缩写,是.Net代码转化成机器语言的一个中间语言,因此又把IL语言称之为反汇编语言。
IL工具有哪些?
俗话说,工欲善其事必先利其器。了解IL就要首先从使用工具开始。在.Net世界里有数个不同的IL工具,包含编译器和反编译器。最经典的编译和反编译利器就是.Net Framework自带的ILASM.exe和ILDASM.exe工具,同时还有其他,例如Reflector.exe,ILSay.exe等等。
具体IL指令介绍
要了解IL的指令,我们以一个非常简单的程序开始,源代码如下:
using System;
namespace HelloWorld
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
相信大家对这段代码再熟悉不过,对于编译后的可执行文件应用ILDasm.exe反编译工具,还原为文本MSIL编码,编译后的IL结构中,包含了MANIFEST和HelloWorld类,如下图所示:
其中MANIFEST是附加信息表,主要包含了程序集的一些属性,例如程序集名称、版本号、哈希算法、程序集模块等等,以及对外部引用程序集的引用项;下面我们重点根据Hello World类来介绍IL指令
首先是Hello World类型,IL代码如下:
>.class表明了HelloWorld是一个类,该类型继承自外部程序集mscorlib的System.Object类。
>public为访问控制权限,表示具有最高的访问权限,为访问成员没有限制。
>auto表示程序加载时内存的布局是有CLR决定的,而不是程序本身。
>.ansi属性则为了在没有被托管和被托管的代码之间实现无缝转换。没有被托管的代码,值的是没有运行在CLR运行库之上的代码,例如原来的C,C++代码等。
>.beforefieldinit属性为HelloWorld提供一个附加信息,用于标记运行库可以在任何时候执行类型构造函数方法,只要该方法在第一次访问其静态字段之前执行即可。如果没有beforefieldinit则运行库必须在某个精确时间执行构造函数方法,从而影响性能优化。
然后是.ctor方法,代码如下:
>.cil managed说明方法体中为IL代码,指示编译器编译为托管代码。
>.maxstack表明执行构造函数.ctor期间的评估堆栈可容纳数据项的最大个数。关于评估堆栈,其用于保存方法所需变量的值,并在方法执行结束时清空,或者存储一个返回值。
>.IL_0000,是一个标记码行开头,一般来说,IL_标记之前的部分为变量的声明和初始化。
>.ldarg.0(ldarg即load argument)表示装载第一个成员参数,在实例方法中值的是当前实例的引用,该引用将用于积累构造函数中调用。
>.call指令一般用于调用静态方法,因为静态方法是在编译期指定的,而在此处call并非调用静态方法,而是构造函数.ctor(),也是在编译期指定的;而另一个指令callvirt则表示调用实例方法,它的调用过程有异于call,函数的调用时在运行时确定的,首先会检查被调用函数是否为虚函数,如果不是就直接调用,如果是则向下检查子类是否有重现,如果有就调用重写实现,如果没有还调用原来的函数。
>.ret表示执行完毕,返回。
最后是Main方法,代码如下:
>.entrypoint指令表明了CLR加载程序HelloWorld.exe时,是首先从.entrypoint方法开始执行的,也就是表明Main方法将作为程序的入口函数。没有托管程序必须有且只有一个入口程序。这区别于将Main函数作为程序入口标志。
>.ldstr(即load string)指令表示将字符串压栈,“Hello World!”字符串将被移到stack顶部。CLR通过从元数据表中获取文字常量来构造string对象。
>.hidebysig属性用于表示如果当前类作为父类时,类中的方法不会被子类继承。因此HelloWorld子类中不会看到Main方法。
>.关于注释,IL代码中注释和C#等高级语言的注释相同。
参考:
《你必须知道的.Net》