MSIL Методы, не требующие рет

Недавно я поиграл с написанием 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 может декомпилировать оба метода без проблем.

Может кто-нибудь объяснить, что здесь происходит?

1 ответ

Решение

Я думаю, это потому, что CLR иногда принимает IL, который недопустим, и только когда он встречает IL, который он на самом деле не может выполнить, он выбрасывает InvalidProgramException, Я предполагаю, что это сделано из соображений производительности: проверка того, что IL следует всем правилам, будет слишком медленной.

Если вы хотите убедиться, что ваш IL действителен, вы должны использовать PEVerify для него.

И когда у вас есть неверный код, неудивительно, что некоторые инструменты, такие как DotPeek, не могут его обработать.

Другие вопросы по тегам