Поделиться через


Особенности написания кода пролога и эпилога

Блок, относящийся только к системам Майкрософт

Прежде чем писать собственные последовательности кода пролога и эпилога, важно понять, как выложен кадр стека. Также полезно знать, как использовать __LOCAL_SIZE символ.

Макет кадра стека

В данном примере показан стандартный код пролога, который может присутствовать в 32-разрядной функции.

push        ebp                ; Save ebp
mov         ebp, esp           ; Set stack frame pointer
sub         esp, localbytes    ; Allocate space for locals
push        <registers>        ; Save registers

Переменная localbytes представляет число байтов, которые требуются в стеке для локальных переменных, а переменная <registers> — это заполнитель, представляющий список сохраняемых в стеке регистров. После проталкивания регистров можно разместить в стеке все другие необходимые данные. Ниже приведен соответствующий код эпилога.

pop         <registers>   ; Restore registers
mov         esp, ebp      ; Restore stack pointer
pop         ebp           ; Restore ebp
ret                       ; Return from function

Стек всегда расширяется в направлении вниз (от старших адресов памяти к младшим). Указатель базы (ebp) указывает на помещенное в стек значение ebp. Область локальных переменных начинается с адреса ebp-4. Для доступа к локальным переменным необходимо вычислить смещение от ebp путем вычитания соответствующего значения из ebp.

__LOCAL_SIZE

Компилятор предоставляет символ для __LOCAL_SIZEиспользования в блоке встроенного сборщика кода пролога функции. Этот символ служит для выделения пространства локальным переменным в кадре стека пользовательского кода пролога.

Компилятор определяет значение __LOCAL_SIZE. Это значение представляет общее количество байтов всех определяемых пользователем локальных переменных и временных переменных, создаваемых компилятором. __LOCAL_SIZE можно использовать только в качестве немедленного операнда; его нельзя использовать в выражении. Значение этого символа не следует изменять и переопределять. Например:

mov        eax, __LOCAL_SIZE           ;Immediate operand--Okay
mov        eax, [ebp - __LOCAL_SIZE]   ;Error

В следующем примере голой функции, содержащей пользовательские последовательности пролога и эпилога, используется __LOCAL_SIZE символ в последовательности пролога:

// the__local_size_symbol.cpp
// processor: x86
__declspec ( naked ) int main() {
   int i;
   int j;

   __asm {      /* prolog */
      push   ebp
      mov      ebp, esp
      sub      esp, __LOCAL_SIZE
      }

   /* Function body */
   __asm {   /* epilog */
      mov      esp, ebp
      pop      ebp
      ret
      }
}

Завершение блока, относящегося только к системам Майкрософт

См. также

Вызовы функций с атрибутом naked