Вопросы, связанные с написанием кода пролога и эпилога
Блок, относящийся только к системам 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
}
}