【问题标题】:MSIL Methods not requiring ret不需要 ret 的 MSIL 方法
【发布时间】:2013-08-20 03:09:13
【问题描述】:

我最近一直在尝试编写 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 可以毫无问题地反编译这两种方法。

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

【问题讨论】:

    标签: methods return cil il ilasm


    【解决方案1】:

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

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

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

    【讨论】:

    • 我想是的,只是我很惊讶 ilasm 如此高兴地接受从未(明确地)在没有警告的情况下返回的代码。此外,在编译我的代码之后验证我的代码似乎非常违反直觉,但 PEVerify 确实发现了错误。
    • @IllidanS4 但这不仅仅是关于 ilasm,它也是关于 CLR,它也接受并执行此代码。
    猜你喜欢
    • 2011-05-01
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    相关资源
    最近更新 更多