我没有清楚地理解LEAVE功能,这是那些2个指令凝:需要约LEAVE指令汇编语言编写了一些解释
MOV ESP, EBP
POP EBP
所以MOV ESP, EBP
移动ESP向下EBP的水平(开始堆栈)。
然后POP EBP
,移动ESP指向的值并将其影响到EBP,并且还向下移动ESP一步。
但我真的没有看到,这两个操作如何与留下函数(这是LEAVE的目的)的事实相关联。
你能帮我澄清一下吗?
我没有清楚地理解LEAVE功能,这是那些2个指令凝:需要约LEAVE指令汇编语言编写了一些解释
MOV ESP, EBP
POP EBP
所以MOV ESP, EBP
移动ESP向下EBP的水平(开始堆栈)。
然后POP EBP
,移动ESP指向的值并将其影响到EBP,并且还向下移动ESP一步。
但我真的没有看到,这两个操作如何与留下函数(这是LEAVE的目的)的事实相关联。
你能帮我澄清一下吗?
一个共同的序幕,在例行的启动指令序列,在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
可用于优化代码空间。
“LEAVE”的作用就是撤销“ENTER”的作用,即“释放”由“ENTER”创建的堆栈帧。 – Michael
所以,它是删除当前的堆栈帧,并指向下面的? – juRioqs75
它平衡了ENTER指令的功能。设置一个堆栈框架并再次拆除。你需要忘记这些指令是存在的,它们只有在20多年前处理器还没有超标量时才有意义。 –