6

我最近一直在尝试编写 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() 都没有返回语句。Foo() 甚至有返回值!编译并运行此代码后,我得到以下输出:

你好世界!来自Foo的你好!再见!Foo 返回:42!

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

奇怪的是,当我试图用 DotPeek 反编译该方法时,它完全拒绝用// ISSUE: unable to decompile the method.

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

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

4

1 回答 1

5

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

如果你想验证你的 IL 是否有效,你应该在它上面使用 PEVerify。

而且当您有无效代码时,DotPeek 等一些工具无法处理它也就不足为奇了。

于 2013-08-18T12:23:24.903 回答