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


Вопросы, связанные с написанием кода пролога и эпилога

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

Перед написанием собственных последовательностей кодов пролога и эпилога важно понимать, как размещается кадр стека. Полезно также знать, как использовать символ __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

В следующем примере функции с атрибутом naked, содержащей пользовательские последовательности пролога и эпилога, символ __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