2017-01-28 11 views
1

я не ясно понимал, функции ОТПУСКА, это конденсат из этих 2 инструкции:нужны некоторые пояснения по поводу инструкции LEAVE на языке ассемблера

MOV ESP, EBP 
POP EBP 

Так MOV ESP, EBP двигается ESP вниз до уровня EBP (начало стек).

Затем POP EBP, перемещает значение, указанное ESP, и воздействует на него на EBP, а также перемещает ESP на один шаг вниз.

Но я действительно не вижу, как эти две операции связаны с фактом оставления функции (что является целью LEAVE).

Помогите мне прояснить это, пожалуйста?

+0

Цель 'LEAVE' состоит в том, чтобы отменить действие' ENTER', т. Е. «Освободить» фрейм стека, созданный «ENTER». – Michael

+0

так, чтобы удалить текущий стек стека и указать на него ниже? – juRioqs75

+2

Он балансирует то, что делает инструкция ENTER. Настройка фрейма стека и его разматывание снова. Вы должны забыть, что эти инструкции существуют, они имели смысл только 20 лет назад, когда процессоры еще не были суперскалярными. –

ответ

2

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