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, не могут его обработать.