2017-01-28 50 views
1

我没有清楚地理解LEAVE功能,这是那些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),以及如何好这个模型的比例更大局部变量或参数。
由于这个原因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可用于优化代码空间。