IL的全名叫Intermediate Language,.NET的任何一门语言(其中包括C#、VB.NET等)都可以编译为IL,可以说我们可以通过了解IL来熟悉.NET这门技术.
我们现在来看一个经典的Hello World程序(该文件命名为FirstIL.il):
2 .assembly extern mscorlib{}
3 .method static void main()
4 {
5 .entrypoint
6 ldstr " Hello World! "
7 call void [mscorlib]System.Console::WriteLine( class System.String)
8 ret
9 }
通过在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727目录下的ilasm.exe来编译该文件:
ilasm /nologo /quite FirstIL.il
OK,在当前目录下生成FirstIL.exe文件,直接执行该文件,输出:Hello World!
这是一个最简单的IL程序,让我们来详细介绍该程序:
第一行:定义该程序的编译目标
第二行:加载外部库文件mscorlib
第三行:创建一个静态方法main,该方法没有任何返回值
第五行:设定该程序的入口
第六行:将一段字符串Hello World!压入栈中
第七行:利用mscorlib库中的Console.WriteLine输出栈内的数据
第八行:结束该函数
我们会看到在上面的程序集中有一些行是以一个点(dot)开始的,以一个dot开始代表在编译该文件时应该执行的动作,如加载一个部库、定义一个方法等。没有以一个dot开始的就是一个实际的汇编指令。
.assembly用于加载外部库或者定义编译目标.一个可执行文件的开始必须定义一个编译目标,否则在执行时抛出异常
.method用于定义一个方法,并说明其返回值和方法名
.entrypoint用于说明当执行文件时的入口,正如我们在写C#控制台程序的时候,程序总是从Main函数开始执行那样,我们可以写多个函数:
2 .assembly extern mscorlib{}
3 .method static void main()
4 {
5 .entrypoint
6 ldstr " Hello World! "
7 call void [mscorlib]System.Console::WriteLine( class System.String)
8 ret
9 }
10 .method static void show()
11 {
12 ldstr " Hello,Zhang Liang "
13 call void [mscorlib]System.Console::WriteLine( class System.String)
14 }
但我们在编译后执行时发现,程序总是输出Hello World。
如果一个程序中包括两个.entrypoint可以不呢?答案当然是不可以的,也正如C#控制台程序那样一个程序中只能有唯一的一个静态的Main函数,但是有趣的是.entrypoint可以放在函数内的任何一个地方,因为它仅仅用于标示该函数是程序的入口而已.
2 .assembly extern mscorlib{}
3 .method static void main()
4 {
5 ldstr " Hello World! "
6 call void [mscorlib]System.Console::WriteLine( class System.String)
7 ret
8 .entrypoint
9 }
ret代表函数结束,没有ret也能通过编译,但在执行时会发生错误,函数都应该采用ret来结尾。
ldstr表示的意思是“将一个字符串压入栈中”,以后调用的函数将从栈内获取参数。
汇编指令call用于调用一个函数,call的语法为:
call 函数返回值 [程序集]命名空间.类名.函数名(参数类型)