Share via


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

Microsoft 固有の仕様 →

一般に、__asm ブロックが開始する際に、レジスタに任意の値があるとは仮定しないでください。 レジスタ値は、別の __asm ブロックにわたって保持されているとは限りません。 インライン コード ブロックを終了し、別のブロックを開始する場合は、最初のブロックの値を保持するのに、2 番目のブロックのレジスタに依存することはできません。 __asm ブロックは、コントロールの標準フローからのレジスタ値の結果を継承します。

__fastcall の呼び出し規約を使用すると、コンパイラは、スタックではなくレジスタに関数引数を渡します。 これにより、__asm ブロックを持つ関数に問題が生じる可能性があります。どのレジスタにどのパラメーターがあるかを通知する手段が関数にないためです。 関数が EAX でパラメーターを受け取り、すぐに任意のデータを EAX に格納すると、元のパラメーターは失われます。 また、__fastcall で宣言されるすべての関数において ECX レジスタを保持する必要があります。

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

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

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

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

注意

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

END Microsoft 固有の仕様

参照

関連項目

インライン アセンブラー