Поскольку сервисная функция VMM _SelectorMapFlat не имеет стандартной обертки, возможная функция-обертка для нее могла бы выглядеть следующим образом:
#pragma warning (disable: 4035) // Блокировка предупреждения о невозврате
_declspec (naked) void *SelectorMapFlat (DWORD VM, DWORD Sel, DWORD Rsv = 0) {
VMMJmp (_SelectorMapFlat) // Передача управления VMM
(void)(VM, Sel, Rsv); // Имитация использования параметров
}
#pragma warning (default: 4035) // Восстановление предупреждений о невозврате
Квалификатор _declspec (naked)
подавляет генерацию пролога/эпилога, так что от функции остается лишь конструкция VMMJmp. При вызове этой функции-обертки параметры VM, Sel
и Rsv
помещаются в стек, затем туда же помещается адрес возврата, управление передается в функцию-обертку, при этом VMMJmp
передает управление сервисной функции VMM _SelectorMapFlat, не запоминая нового адреса возврата в стеке. VMM использует значения параметров из стека, затем выполняет возврат по адресу, находящемуся на верхушке стека, при этом управление сразу возвращается в точку за вызовом функции-обертки, где находится код, удаляющий из стека параметры и использующий значение, возвращенное VMM в EAX.
Такая схема типична для построения функций-оберток, так как в полной мере использует особенности создания стекового кадра в языках C, а также возможности компилятора Visual C++ по оформлению функций. Без использования VMMJmp пришлось бы делать возврат дважды, а без использования квалификатора naked — дважды помещать в стек список параметров.