组装x86的目的是“输入0,0”

时间:2019-06-26 18:49:25

标签: assembly visual-c++ x86 inline-assembly

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

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

这是我到目前为止所做的,并且效果很好,就像上面的方法一样。但是据我了解,enter 0,0指令在那里释放了堆栈中用于局部变量的空间。我将两个局部变量推入堆栈:push dword ptr[n]。但是,仅当我使用enter这样的enter 8,0指令时,才应该这样做。为两个int变量释放空间。如果尝试这样做,则会出现StackOverflow异常。

__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

1 个答案:

答案 0 :(得分:2)

  

为两个int变量释放空间。

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

  

我将两个局部变量压入堆栈:压入dword ptr [n]。但是,仅当我使用此类输入指令时,才应该这样做:输入8,0。

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

它不会不分配(堆栈)内存,push指令可以使用该内存,但是它使用(堆栈)内存的方式与{{ 1}}指令可以:

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

已经写入push,将仅enter 0,0并初始化push寄存器。使用启用了优化的真实C编译器,在这种情况下,您可能不会获得ebp指令。

  

如果我尝试这样做,则会出现StackOverflow异常。

很难说为什么:

如果您大量调用函数,则函数将需要大量堆栈。通过使用enter而不是enter 8,0,您需要为函数参数enter 0,0增加8*n个字节。

如果使用n时堆栈已经快满了,那么使用enter 0,0时堆栈肯定会满了。

第二件事是您的拆卸未完成:

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

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

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