Общий пролог, последовательность команд в начале подпрограммы, в 32-битной и 16-битной эры было
push ebp
mov ebp, esp
sub esp, <local_var_size>
push <clobbered_reg1>
push <clobbered_reg2>
...
Ничто не случайно здесь, порядок обучения имеет важное значение, мы в конечном итоге с
|parN | <-- EBP + 04 + n*4 par1..parN = Routine parameters
... ... ra = Return address
|par2 | <-- EBP + 0ch o ebp = Original (caller) EBP
|par1 | <-- EBP + 08h lvar1..lavarM = Local variables
|ra | <-- EBP + 04h creg1..cregK = Clobbered registers
|o ebp| <-- EBP
|lvar1| <-- EBP - 04h
|lvar2| <-- EBP - 08h
... ...
|lvarM| <-- EBP - m*4
|creg1|
|creg2|
...
|cregK| <-- ESP
Посмотрите, как все данные будут легко доступен с помощью соответствующего указателя из ebp
(параметров, как последовательные положительные сдвигов больше или равно 8, местный Варс как отрицательные смещения меньше или равен 4) и насколько хорошо эта модель масштабируется для большего количества r локальных варов или параметров.
По этой причине ebp
называется указателем кадра.
Эпилог должен отменить все это.
Одним из возможных вариантов является
pop <clobbered_regK>
...
pop <clobbered_reg1>
add esp, <local_var_size>
pop ebp
ret n*4
Однако это предполагает повторение <local_var_size>
- это легко забыть держать обе версии в синхронизации.
Мы можем воспользоваться тем фактом, что ebp
является значением esp
перед распределением локальных варов, таким образом, восстанавливая это значение, мы фактически освобождаем их всех.
pop <clobbered_regK>
...
pop <clobbered_reg1>
mov esp, ebp
pop ebp
ret n*4
Но третья и вторая команда от конца то, что делает leave
инструкции. Таким образом:
pop <clobbered_regK>
...
pop <clobbered_reg1>
leave
ret n*4
является эквивалентным прологом.
enter
является плохой инструкции в то время как leave
может быть использована для оптимизации кода пространства.
Цель 'LEAVE' состоит в том, чтобы отменить действие' ENTER', т. Е. «Освободить» фрейм стека, созданный «ENTER». – Michael
так, чтобы удалить текущий стек стека и указать на него ниже? – juRioqs75
Он балансирует то, что делает инструкция ENTER. Настройка фрейма стека и его разматывание снова. Вы должны забыть, что эти инструкции существуют, они имели смысл только 20 лет назад, когда процессоры еще не были суперскалярными. –