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() にも return ステートメントがないことに注意してください。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 に答える