CIL之——输出Hello World

既然了解了CIL是什么、长什么样子,那么下面就让我们写出第一个CIL语言的程序吧!无论哪种语言,入门程序都是输出Hello World,那么我们就用CIL实现一个输出Hello World的小程序。
我是在Windows系统中使用Notepad++来写CIL代码的,CIL文件的后缀名是.il,所以我们先新建一个名为HelloWorld.il的文本文件,然后就能在HelloWorld.il文件中编写CIL代码了。
与C#不同,CIL并不要求方法必须属于某个类,也不要求类必须属于某个命名空间,所以我们无需定义一个类,只需要声明一个主函数即可。在CIL中我们管这种函数叫做”entrypoint”,即入口函数,只要定义为entrypoint,函数名叫不叫Main无所谓,为了演示这一点,我们的函数名就叫做Show。

.method public static void Show()
{
    .entrypoint
    .maxstack 1

    ldstr "Hello World"
    call void [mscorlib]System.Console::WriteLine(string)
    call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    ret
}

上面就是我定义的Show方法,它和一般的语言一样,包括方法签名和方法体。但在CIL语言中,方法的定义有以下需要注意的地方:

  1. 方法的定义以.method作为标识,方法可以属于某个类,也可以不属于某个类。
  2. 和C#一样,CIL程序的入口也必须是静态的,也就是意味着调用这个入口函数并不需要某个类的实例。当然,需要使用static关键字来标识。
  3. 程序的入口以.entrypoint作为标识,它表明了该方法是CIL程序的入口,程序的入口只能有一个。
  4. .maxstack表明了预计使用的堆栈槽个数,在本例中是1,因为我们只是把”Hello World”这个字符串压栈。举个例子,如果我们需要实现2数相减的减法,则需要2个堆栈槽,首先需要将2个数压栈,之后sub操作符将栈顶的2个数弹出并求差值,最后将结果压栈,所以最多需要2的栈槽。
  5. ldstr操作符将”Hello World”压栈,供之后的WriteLine方法使用。
  6. call调用了mscorlib程序集中System.Console类中的WriteLine方法。这里call指明了WriteLine的完整签名(void [mscorlib]System.Console::WriteLine(string)),所以运行时能正确地加载WriteLine方法。
  7. 如果方法有返回值的话,ret操作符会将结果返回给调用者;如果方法没有返回值,执行ret操作意味着方法的结束。
  8. 有一些同学可能看过很多CIL语言的代码,发现它们每一条语句之前都有一个类似”IL_0000:”这样的东西,其实IL_XXXX的作用是表示行号,没有它也不会影响程序的运行。

一个简单的Hello World的确能带来一些基本的知识点,但是这个HelloWorld.il文件编译之后还不能运行。因为本例中调用了mscorlib程序集中的WriteLine方法和ReadKey方法,所以我们还要加入一些程序集的信息才行,完整的代码如下:

.assembly extern mscorlib
{
    .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
    .ver 4:0:0:0
}
.assembly GuoAssembly
{
    .ver 0:0:0:0
}
.module GuoModule
.class public GuoNameSpace.Program extends [mscorlib]System.Object
{
    .method public static void Show()
    {
        .entrypoint
        .maxstack 1

        ldstr "Hello World"
        call void [mscorlib]System.Console::WriteLine(string)
        call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
        ret
    }
}

请注意一下本例中类的名字为GuoNameSpace.Program,它表示创建了一个Program类,并且这个Program类属于GuoNameSpace命名空间。除此之外还有一种显式指定命名空间的写法,代码如下:

.namespace GuoNameSpace
{
    .class public Program extends [mscorlib]System.Object
    {
        .method public static void Show()
        {
            .entrypoint
            .maxstack 1

            ldstr "Hello World"
            call void [mscorlib]System.Console::WriteLine(string)
            call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
            ret
        }
    }
}

无论是显式指定命名空间还是隐式指定命名空间,在调用类时都要写类的全名称,即namespaceName+className。利用ilasm.exe对HelloWorld.il文件进行编译,生成HelloWorld.exe,双击运行可以看到屏幕输出了”Hello World”,第一个CIL程序圆满完成。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

changuncle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值