Фрейм стека и возврат

Итак, я сейчас читаю "Практический обратный инжиниринг" - x86, x64, ARM, ядро ​​Windows, инструменты реверсирования и обфускации. Книга включает следующий пример, объясняющий фрейм стека.

addme (x, y)

01: 004113A0 55 push ebp
02: 004113A1 8B EC mov ebp, esp
03: ...
04: 004113BE 0F BF 45 08 movsx eax, word ptr [ebp+8]
05: 004113C2 0F BF 4D 0C movsx ecx, word ptr [ebp+0Ch]
06: 004113C6 03 C1 add eax, ecx
07: ...
08: 004113CB 8B E5 mov esp, ebp
09: 004113CD 5D pop ebp
10: 004113CE C3 retn

Вызов функции

01: 004129F3 50 push eax ;param2
02: ...
03: 004129F8 51 push ecx ;param1
04: 004129F9 E8 F1 E7 FF FF call addme
05: 004129FE 83 C4 08 add esp, 8

Я понимаю, что в строке 10 функции addme мы выполняем mov ebp, esp, чтобы запустить новый кадр стека для текущей функции, но я не понимаю, почему мы вызываем mov esp, ebp прямо перед pop. Если я правильно понимаю, это текущее состояние стека перед вызовом mov esp, выполняется ebp.

           TOP
**************************
*         param2         *
**************************
*         param1         *
**************************
*         return addrs   *
**************************
*         old edp        *
**************************
esp and edp are pointing after odl edp.

Так почему же был сделан вызов mov esp, ebp?

Если что-то не так, пожалуйста, дайте мне знать. Спасибо.

1 ответ

Решение

Пара инструкций

mov esp, ebp
pop ebp

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

leave

но это может быть медленнее, чем использование двух инструкций (см. этот пост).

Но это mov esp, ebp действительно нужно здесь?

Это зависит от того, что делается внутри функции. Компилятор обычно добавляет эту строку, потому что он удаляет локальные переменные из стека. В стеке также могут быть другие значения, еслиreturnиспользуется в середине функции, где промежуточные результаты также могут быть в стеке. представитьreturn вызывается с этим назначением стека:

+---------------------------+
|         param 2           |
+---------------------------+
|         param 1           |
+---------------------------+
| old eip (return address)  |
+---------------------------+
| old ebp (last stackframe) | <-- ebp
+---------------------------+
|     local variable 1      |
+---------------------------+
|     local variable 2      |
+---------------------------+
|       interim value       | <-- esp
+---------------------------+

Промежуточные значения могут возникнуть, если регистров больше не хватает для хранения всех значений. А такжеebpуказывает на старый EBP, а не в ячейку памяти, после этого (см Значит лиpush espобновить ESP до или после сохранения?)

Другие вопросы по тегам