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

MSVC++ ではできることを覚えています__declspec(naked)。つまり、自分でスタックを処理する必要があります。つまり、上書きしたすべてのレジスタを保存して復元する必要があります。

呼び出し規約に依存するため、これを適切に行うための唯一のルールはありません。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 に答える
5

コールスタックを維持しています。関数を次のように定義した場合

int NativeLoop() { }

同じアセンブリが表示されます。

于 2010-02-10T16:55:06.517 に答える
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 に答える