我正在阅读汇编语言艺术(Randall Hyde,链接到亚马逊),我在那本书中尝试了一个控制台应用程序.这是一个使用Win32 API函数为自己创建一个新控制台的程序.该程序包含一个名为的过程LENSTR,它将字符串的长度存储在EBP寄存器中.该函数的代码如下:
LENSTR PROC
ENTER 0, 0
PUSH EAX
;----------------------
CLD
MOV EDI, DWORD PTR [EBP+08H]
MOV EBX, EDI
MOV ECX, 100 ; Limit the string length
XOR AL, AL
REPNE SCASB ; Find the 0 character
SUB EDI, EBX ; String length including 0
MOV EBX, EDI
DEC EBX
;----------------------
POP EAX
LEAVE
RET 4
LENSTR ENDP
Run Code Online (Sandbox Code Playgroud)
你能在这里解释一下enter和leave命令的用法吗?
Jer*_*fin 40
Enter创建堆栈帧,并leave销毁堆栈帧.有了0,0参数enter,它们基本上相当于:
; enter
push ebp
mov ebp, esp
; leave
mov esp, ebp
pop ebp
Run Code Online (Sandbox Code Playgroud)
虽然它没有在您发布的代码中使用,enter但支持比上面显示的简单push/mov组合更多.第一个参数,用于enter指定为局部变量分配的空间量.例如,enter 5, 0大致相当于:
push ebp
mov ebp, esp
sub esp, 5
Run Code Online (Sandbox Code Playgroud)
Enter 还支持像Pascal这样可以使用嵌套函数/过程的语言:
procedure X;
procedure Y;
begin
{ ... }
end
begin
{ ... }
end
Run Code Online (Sandbox Code Playgroud)
在这种情况下,Y不仅可以访问自己的局部变量,还可以访问本地变量X.这些可以嵌套到任意深度,因此你可以在其Z内部Y访问自己的局部变量,以及变量Y和变量X.的第二个参数enter指定了嵌套深度,因此X将使用enter Sx, 0,Y将使用enter Sy, 1和Z将使用enter Sz, 2(其中Sx,Sy和Sz表示的局部变量的大小X,Y和Z分别地).
这将创建一个堆栈帧链,以提供Z对本地Y和等的变量的访问X.如果函数是递归的,那么这变得相当重要,因此调用Z不仅可以将堆栈向上移动到最近的两个堆栈帧 - 它需要跳过之前调用自身的堆栈帧,然后直接返回为词法父函数/过程堆叠帧,这与递归时的调用者不同.
这种复杂性也是C和C++禁止嵌套函数的原因.鉴于进入/离开的存在,它们在英特尔处理器上相当容易支持,但在缺乏这种直接支持的许多其他处理器上可能要困难得多.
这也至少有助于解释另一个...的特征enter- 对于这里使用的普通情况(即enter 0, 0),它比使用push/ 的等效物慢得多mov.
Ton*_*ion 15
这是该功能的堆栈帧(激活记录)的设置.在内部,它通常看起来像这样:
push( ebp ); // Save a copy of the old EBP value
mov( esp, ebp ); // Get ptr to base of activation record into EBP
sub( NumVars, esp ); // Allocate storage for local variables.
Run Code Online (Sandbox Code Playgroud)
然后,当要再次销毁堆栈框架时,您必须执行以下操作:
mov( ebp, esp ); // Deallocate locals and clean up stack.
pop( ebp ); // Restore pointer to caller's activation record.
ret(); // Return to the caller.
Run Code Online (Sandbox Code Playgroud)
以下是使用HLA对它的更好解释.虽然在你正在阅读的书中有很好的解释,因为我也有那本书,我已经阅读了解释它的部分.