3

我有一些代码(内联汇编)。

void NativeLoop()
{
    int m;
    __asm
    {
        PUSH ECX
        PUSH EDX
        MOV  ECX, 100000000
NEXTLOOP:
        MOV  EDX, ECX
        AND  EDX, 0X7FFFFFFF
        MOV  DWORD PTR m, EDX
        DEC  ECX
        JNZ  NEXTLOOP
        POP  EDX
        POP  ECX
    }
}

MS C++ 自动将这些代码(标有 **)添加到我的程序中。
为什么?
如何避免?

  **push        ebp  
  **mov         ebp,esp 
  **push        ecx  
  push        ecx  
  push        edx  
  mov         ecx,5F5E100h 
NEXTLOOP:
  mov         edx,ecx 
  and         edx,7FFFFFFFh 
  mov         dword ptr m,edx 
  dec         ecx  
  jnz         NEXTLOOP
  pop         edx  
  pop         ecx  
  **mov         esp,ebp 
  **pop         ebp  
  **ret
4

5 回答 5

20

它是标准的函数进入和退出代码。它建立并拆除堆栈框架。如果你不想要它,你可以使用 __declspec(naked)。如果您这样做,请不要忘记包括 RET。

但是,您的代码段依赖于有效的堆栈帧,您的“m”变量需要它。它在 [ebp-10] 得到解决。如果没有前导码,ebp 寄存器将无法正确设置,并且您将破坏调用者的堆栈帧。

于 2010-02-10T16:59:17.897 回答
5

它正在维护调用堆栈。如果您将函数定义为

int NativeLoop() { }

您会看到相同的程序集。

于 2010-02-10T16:55:06.517 回答
5

我记得你可以__declspec(naked)在 MSVC++ 中,这意味着你必须自己处理堆栈,这意味着你必须保存你破坏的每个寄存器,并恢复它。

没有唯一的规则可以正确地做到这一点,因为它取决于调用约定。请参阅http://en.wikipedia.org/wiki/X86_calling_conventions

旁注:在 gcc 中,您向编译器明确说明您将驱动的内容无效,以便 gcc 将输出更优化的保存/恢复/堆栈帧代码(如果有)。在 MSVC 中,asm 对编译器来说主要是一个黑盒,它通常/总是最糟糕的。

请参阅http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#ss5.3,gcc 内联 asm 语法更丑陋,但实际上更有效。

于 2010-02-10T16:59:03.647 回答
4
  **push        ebp  ;save EBP register
  **mov         ebp,esp  ;Save the stackframe
  **push        ecx  ; So that the variable `m` has an address
;...
  **mov         esp,ebp ;restore the stack frame to it's original address
  **pop         ebp   ;restore EBP register
  **ret ;return from function call
于 2010-02-10T17:00:40.437 回答
0

如果您可以搜索 C++ 调用约定,您将更好地理解编译器在做什么。

于 2010-02-10T16:58:22.377 回答