MSIL方法不需要ret

时间:2013-08-18 01:23:15

标签: methods return cil il ilasm

我最近一直在玩MSIL并用ilasm编译它,当时我注意到方法确实需要从方法结束返回一个ret指令; 例如,我应该应该写这样的代码:

.method static void Main()
{
    .entrypoint
    ldstr "Hello World!"
    call void [mscorlib]System.Console::WriteLine(string)
    ret //I am returning properly
}

但是,如果省略ret,代码仍会运行并输出“Hello World!”完美。起初我认为这可能是入口点方法特有的,但是ilasm很高兴地编译这个代码既没有警告也没有错误:

.assembly Program{}
.assembly extern mscorlib{}
.method static void Main()
{
.entrypoint
ldstr   "Hello World!"
call    void    [mscorlib]System.Console::WriteLine(string)
ldstr   "Foo returned: {0}!"
call    int32   Foo()
box     int32
call    void    [mscorlib]System.Console::WriteLine(string, object)
}
.method static int32 Foo()
{
ldstr   "Hello from Foo!"
call    void    [mscorlib]System.Console::WriteLine(string)
ldstr   "GoodBye!"
call    void    [mscorlib]System.Console::WriteLine(string)
ldc.i4  42
}

请注意,Main()和Foo()都没有return语句。 Foo()甚至有一个返回值! 编译并运行此代码时,我得到以下输出:

Hello World! 来自Foo的你好! 再见! Foo回来了:42!

该程序也正常终止。然后我想也许ilasm是自动插入ret语句,但是在用ildasm查看程序之后,这些方法与上面的代码相同,即没有返回。

奇怪的是,当我尝试使用DotPeek反编译该方法时,它拒绝用// ISSUE: unable to decompile the method.替换两个方法体

如果我添加了ret语句并重新编译,DotPeek可以毫无问题地反编译这两种方法。

有人可以解释一下这里发生了什么吗?

1 个答案:

答案 0 :(得分:5)

我认为这是因为CLR有时会接受无效的IL,并且只有当遇到IL它实际上无法执行时,它才会抛出InvalidProgramException。我的猜测是出于性能原因这样做:验证IL遵循所有规则会太慢。

如果您想验证您的IL是否有效,您应该使用PEVerify。

当你的代码无效时,像DotPeek这样的工具无法处理它就不足为奇了。