Как правило, вы должны поместить текущее значение EBP
в стек, прежде чем перемещать значение ESP
в EBP
. EBP
- это регистр «сохранения-вызова» на 32-битных платформах. Это означает, что если вы собираетесь изменить его в функции, вы должны сначала сохранить его.
Если вы хотите, чтобы ваша функция возвращала значение того, куда указывает стек (или куда она вернется после вызова функции), лучше всего сделать следующее:
void* get_stack_addr()
{
void* stack_ptr = NULL;
//on 32-bit systems
//EBP is pointing at top of stack frame
//EBP + 4 is the return instruction address
//EBP + 8 is the value that was in ESP before function call for a function with no arguments
__asm__
(
"movl %%ebp, %0\n\t"
"addl $8, %0\n\t"
: "=r" (stack_ptr)
);
return stack_ptr;
}
Таким образом, EAX
теперь содержит адрес значения, на которое указывал стек до вызова get_stack_addr()
. Если вы только что вернули значение ESP
в функции, вы на самом деле понятия не имеете, на что указываете, поскольку компилятор часто дополняет стек в функции C / C ++, чтобы поддерживать правильное выравнивание стека. Он также часто резервирует место в стеке для всех локальных переменных, что опять-таки скинет вычисление стека. Используя EBP
, который указывает на вершину стекового фрейма, вы можете точно рассчитать на 32-битной платформе значение стека до вызова функции. Наконец, мы помещаем возвращаемое значение в EAX
, поскольку в большинстве двоичных интерфейсов приложений ОС для C / C ++ EAX
содержит возвращаемое значение функции, а не EBP
.
Еще одна вещь ... если вы хотите запустить параметры в стеке для фактической функции, которая вызывает get_stack_addr()
, то измените movl %%ebp, %0\n\t
на movl (%%ebp), %0)\n\t
. Таким образом, теперь вы получаете предыдущий базовый указатель стекового кадра (т. Е. Базовый указатель стекового кадра вызывающего абонента), и, добавив значение +8 к этому адресу, вы получаете либо начало сохраненных параметров выше адреса возврата, или вы смотрите адрес, указывающий на кадр стека для вызывающей стороны текущей функции (т. е. предыдущего кадра стека).
В качестве улучшения "leal 8(%%ebp), %0\n\t"
можно заменить:
"movl %%ebp, %0\n\t"
"addl $8, %0\n\t"
Эта инструкция leal
добавит 8 к значению EBP и сохранит результат в выходном операнде.