汇编 x86 "enter 0,0" 的目的是什么

Assembly x86 what's the purpose of "enter 0,0"

目前我正在使用 NASM 学习 x86 的汇编。我尝试编写以下计算斐波那契数的函数:

unsigned int fibonacci(unsigned int n) {
    if (n < 2)
        return 1;
    else
        return fibonacci(n - 1) + fibonacci(n - 2);
}

这就是我目前所做的,效果很好,与上述方法完全一样。但据我所知, enter 0,0 指令是为了在堆栈中释放 space 用于局部变量。我将两个局部变量压入堆栈:push dword ptr[n]。但是,如果我像这样使用 enter 指令,这难道不应该是可能的吗:enter 8,0。为两个 int 变量释放 space。如果我尝试这样做,我会收到 Whosebug 异常。

__declspec(naked) unsigned int fibonacci2(unsigned int n) {
    __asm {
        enter 0,0
        cmp dword ptr [n], 2
        jae elsee
        mov eax, 1
        jmp end
        elsee:
        push dword ptr[n] // Here I am pushing two local variables to the stack.
        push dword ptr[n] // 2 * 4 Bytes
        dec [ebp-4]
        dec [ebp-8]
        dec [ebp-8]
        push[ebp-4]
        call fibonacci2     
        mov [ebp-4], eax
        push [ebp-8]
        call fibonacci2
        add eax, [ebp-4]
        end:
        leave
        ret
    }
 }

这是函数的编译版本:

00C426E0  enter       0,0  
00C426E4  cmp         dword ptr [n],2  
00C426E8  jae         fibonacci2+11h (0C426F1h)  
00C426EA  mov         eax,1  
00C426EF  jmp         end (0C42716h)  
elsee:
00C426F1  push        dword ptr [n]  
00C426F4  push        dword ptr [n]  
00C426F7  dec         byte ptr [ebp-4]  
00C426FA  dec         byte ptr [ebp-8]  
00C426FD  dec         byte ptr [ebp-8]  
00C42700  push        dword ptr [ebp-4]  
00C42703  call        _fibonacci2 (0C413BBh)  
00C42708  mov         dword ptr [ebp-4],eax  
00C4270B  push        dword ptr [ebp-8]  
00C4270E  call        _fibonacci2 (0C413BBh)  
00C42713  add         eax,dword ptr [ebp-4]  
end:
00C42716  leave  
00C42717  ret

To free up space for the two int variables.

编译器不需要为局部变量使用堆栈。在某些情况下,它甚至可以完全优化堆栈使用并将局部变量存储在寄存器中。

I push two local variables to the stack: push dword ptr[n]. But shouldn't this only be possible if I use the enter instruction like this: enter 8,0.

enter 指令的作用与您认为的完全相反

不分配(堆栈)可被push指令使用的内存,但它使用(堆栈) 与 push 指令相同的内存方式:

enter 80,0 的工作方式类似于先执行 enter 0,0,然后使用 10 个 random 值执行 push 10 次。这对 "create" 10 个未初始化的局部变量在堆栈上很有用。

如前所述enter 0,0,只会push并初始化ebp寄存器。使用启用了优化的真实 C 编译器,在这种情况下您可能不会获得 enter 指令。

If I try to do so, I get a Whosebug exception.

很难说为什么:

如果您为大量数字调用您的函数,您的函数将需要大量堆栈。通过使用 enter 8,0 而不是 enter 0,0 你需要 8*n 字节更多的函数参数堆栈 n.

如果你的堆栈在使用enter 0,0时已经接近"full",那么在使用enter 8,0时肯定会满。

其次是你的反汇编不完整:

  • 显然,C 编译器在地址 0C413BBh.
  • 处添加了一些名为 _fibonacci2(带下划线)的包装器
  • 反汇编没有将 n 显示为 ebp+8,而是显示为 n

可能是您发布的代码中看不到错误:

  • 它可能位于地址 0C413BBh
  • 的包装器中
  • 或者n没有被正确替换(被ebp+8