进入和离开大会?

dev*_*roy 19 x86 assembly

我正在阅读汇编语言艺术(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)

你能在这里解释一下enterleave命令的用法吗?

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, 1Z将使用enter Sz, 2(其中Sx,SySz表示的局部变量的大小X,YZ分别地).

这将创建一个堆栈帧链,以提供Z对本地Y和等的变量的访问X.如果函数是递归的,那么这变得相当重要,因此调用Z不仅可以将堆栈向上移动到最近的两个堆栈帧 - 它需要跳过之前调用自身的堆栈帧,然后直接返回为词法父函数/过程堆叠帧,这与递归时的调用者不同.

这种复杂性也是C和C++禁止嵌套函数的原因.鉴于进入/离开的存在,它们在英特尔处理器上相当容易支持,但在缺乏这种直接支持的许多其他处理器上可能要困难得多.

这也至少有助于解释另一个...的特征enter- 对于这里使用的普通情况(即enter 0, 0),它比使用push/ 的等效物慢得多mov.

  • @BlackBear:不,他们是指示,但它们是一种"速记"指令 - 你可以在没有它们的情况下完成相同的操作. (5认同)
  • 与“sub esp, x”不同,“enter”不会影响状态标志。更准确的等价物是 `lea esp, [esp - x]` (4认同)

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对它的更好解释.虽然在你正在阅读的书中有很好的解释,因为我也有那本书,我已经阅读了解释它的部分.

  • 你应该省略你的例子中的ret(),因为`leave`不会执行ret (3认同)