Потому что, в отличие от call
, callvirt
или calli
, где кадр стека вызывающего абонента останется в стеке, чтобы его можно было увидеть в будущих обходах безопасности доступа к коду, инициированных (возможно, косвенно) вызываемым объектом, a jmp
инструкция разрушает фрейм стека вызывающей стороны перед переходом к вызываемому и, таким образом, невидима для любых стековых прогулок CAS, которые может вызвать вызываемый.
Редактировать: Я думаю, что naasking прав, потому что ответ выше неправильный. Теперь я думаю, что разница между (проверяемыми) последовательностями tail.call и (не проверяемыми) последовательностями jmp может заключаться в том, что хвостовой вызов требует нажатия аргументы для вызова в стек оценки, где они могут быть проверены обычным способом, тогда как jmp
требует, чтобы стек оценки был пуст и заставляет jump-ee наследовать аргументы jump-er. Вероятно, не было никакой причины усложнять верификатор для проверки jmp
инструкций, но это могло бы быть возможно сделать в условиях, аналогичных тем, которые налагаются на последовательности tail.call
(одна из которых заключается в том, что вызывающий и вызываемый должны быть в одном сборка, которая исключает мою догадку CAS выше, по крайней мере, до явных вызовов .Deny( )
.
Если это так, это будет релевантная часть спецификации: (Раздел III, Раздел 3.37)
Текущие аргументы переданы
к методу назначения.
Стек оценки должен быть пуст
когда эта инструкция выполнена.
соглашение о вызове, номер и тип
аргументы по адресу назначения
должен совпадать с текущим методом.