次の方法で共有


インライン アセンブリでのレジスタの使用および保持

Microsoft 固有の仕様

一般に、__asm ブロックの開始時にレジスタに値が割り当てられるとは想定しないでください。 レジスタの値は、個別の __asm ブロック間で保持されることは保証されていません。 インライン コードのブロックを終了し、別のブロックを開始する場合、2 番目のブロックのレジスタに依存して、最初のブロックの値を保持することはできません。 __asm ブロックは、通常の制御フローから任意のレジスタ値の結果を継承します。

__fastcall 呼び出し規約を使用する場合、コンパイラにより、スタックではなくレジスタに関数の引数が渡されます。 これにより、どのパラメーターがどのレジスタに登録されているかが関数で判別されないため、__asm ブロックのある関数で問題が発生するおそれがあります。 関数が EAX でパラメーターを受け取って、EAX に他の何かを直ちに格納した場合、元のパラメーターは失われます。 また、__fastcall で宣言されたすべての関数で ECX レジスタを保持する必要があります。

このようなレジスタの競合を回避するため、__asm ブロックを含む関数に __fastcall 規則を使用しないでください。 /Gr コンパイラ オプションを使用してグローバルに __fastcall 規則を指定する場合は、__asm ブロックを含むすべての関数を __cdecl または __stdcall で宣言します。 (__cdecl 属性により、その関数に対して C 呼び出し規約を使用するようにコンパイラに指示が出されます)。/Gr を使用してコンパイルしない場合は、__fastcall 属性を使用して関数を宣言しないでください。

__asm を使用して C/c++ 関数でアセンブリ言語を記述する場合、EAX、EBX、ECX、EDX、ESI、または EDI レジスタを保持する必要はありません。 たとえば、「インラインアセンブリを使用した関数の記述」の POWER2.C の例の場合、power2 関数により、EAX レジスタの値は保持されません。 ただし、レジスタ アロケーターは、これらのレジスタを使用してブロック間で __asm 値を格納できないため、これらのレジスタの使用はコードの品質に影響します。 また、インライン アセンブラー コードで EBX、ESI、EDI を使用すると、コンパイラに、プロローグおよびエピローグ関数のレジスタを保存して復元するように強制します。

使用する他のレジスタ (DS、SS、SP、BP、flags レジスタなど) は、__asm ブロックのスコープに対して保持する必要があります。 ESP および EBP レジスタを変更する理由がない場合 (スタックを切り替える場合など) は、それらを保持しておく必要があります。 「インライン アセンブリの最適化」も参照してください。

一部の SSE 型では 8 バイトのスタック アラインメントが必要であり、コンパイラに動的なスタック アラインメント コードの出力が強制されます。 アラインメント後にローカル変数と関数パラメーターの両方にアクセスできるようにするために、コンパイラは 2 つのフレーム ポインターを保持します。 コンパイラによりフレーム ポインターの省略 (FPO) が実行されると、EBP と ESP が使用されます。 コンパイラで FPO が実行されない場合は、EBX と EBP が使用されます。 コードが確実に正しく実行されるようにするには、asm コードで EBX を変更しないでください。これは、関数が動的なスタック アラインメントを必要とする場合にフレーム ポインターが変更される場合があるためです。 8 バイトのアラインメントされた型を関数の外に移動するか、EBX を使用しないようにします。

Note

インライン アセンブリ コードが STD または CLD 命令を使用して方向フラグを変更する場合は、フラグを元の値に戻す必要があります。

Microsoft 固有の仕様はここまで

関連項目

インライン アセンブラー