为什么MS C++将此代码添加到程序集中?

Beh*_*ooz 3 c++ inline-assembly

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

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
    }
}
Run Code Online (Sandbox Code Playgroud)

MS C++ Automagicaly将这些代码(标有**)添加到我的程序中.
为什么?
怎么避免呢?

  **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
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 20

它是标准函数入口和出口代码.它建立并拆除堆栈框架.如果你不想要它,可以使用__declspec(裸).如果你这样做,别忘了包括RET.

但是,您的代码片段依赖于有效的堆栈帧,您的"m"变量需要它.它在[ebp-10]处理.如果没有前导码,ebp寄存器将无法正确设置,您将破坏调用者的堆栈帧.

  • 咦?如果不是局部变量,你认为他的`m`是什么?事实上,他对`dword ptr m`的引用将被转换为基于`ebp`的内存访问,这就是为什么编译器插入的代码是绝对必要的. (4认同)
  • 不仅是RET,还有stackframe/save/restore;) (3认同)

Dav*_*ter 5

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

int NativeLoop() { }
Run Code Online (Sandbox Code Playgroud)

你会看到相同的组件.

  • 也许是因为David的函数是int类型 (4认同)

Seb*_*ach 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语法更难看,但实际上更有效.