さて、スタックはどのように機能しますか?たとえば、命令:
push ax
に等しい:
sub sp, 4
mov sp, ax
ここで、sp はスタック ポインタです。そうですか?
私の質問は、sp レジスタから 4 を減算するポイントは何ですか?
さて、スタックはどのように機能しますか?たとえば、命令:
push ax
に等しい:
sub sp, 4
mov sp, ax
ここで、sp はスタック ポインタです。そうですか?
私の質問は、sp レジスタから 4 を減算するポイントは何ですか?
読むべきだと思う
sub sp, 2 ; AX is only 2 bytes wide, not 4
mov [sp], ax ; store to memory, not writing the register
つまり、ax の値を sp が指すメモリに入れます。
おそらくsub sp, 4、32ビットレジスタをプッシュしたことから来ましたか? スタック ポインタは常にプッシュ オペランド サイズだけ減少します。
push(は、 とは異なり、FLAGS を変更しないことに注意してくださいsub。この疑似コード / 同等のものは、厳密には同等ではなく、大文字と小文字の区別もありません。これらの場合でも動作する疑似コードについては、 Intel のマニュアルまたはこの Q&Apush spを参照してください。)
それはどのようにpush ax機能するかではありません。それが「等しい」ことのコード例は次のとおりです。
sub sp, 2
mov [ss:sp], ax
SP の値を AX で上書きしません。代わりに、SS:SP が指すメモリ アドレスに AX をコピーします (データ セグメントではなく、スタック セグメントを使用します)。ただし、実際には、これは正確ではありません。本当に必要なのは次のようなものです。
mov [tmp], sp
pushf ;push FLAGS
sub [tmp], 2
popf
mov sp, [tmp]
mov [ss:sp], ax
基本的に、push非常に単純なことを行いますが、その単純なことにまつわる詳細は、独自の説明を作成する価値があります。push word [bp - 4]特に、ローカル変数をまだロードしていない場合にローカル変数をプッシュするなどの命令を使用して、メモリからメモリにコピーできること。
[ss:sp]16 ビット アドレッシング モードとしてエンコードできない架空のアドレッシング モードを必要とせず、使用しない代替コード。
mov internal_tmp, sp
lea internal_tmp, [internal_tmp - 2] ; sub without FLAGS
mov [internal_tmp], SRC_OPERAND ; even for a memory source, or for push sp
mov sp, internal_tmp
違いはsub esp, 4フラグを設定しますが、プッシュはフラグを設定しません。また、それはする必要がありますmov [esp],eax。表示されている 16 ビット バージョンは、非常に古い本を使用していることを示しています。16 ビット マシンでプログラミングする人はもういません (おそらく、組み込みマイクロコントローラーを除く)。
x86 では、OF、SF、ZF、ZF、PF、および CF フラグは減算によって設定されますが、フラグは a の影響を受けませんPUSH。
の値をax次に利用可能なスタック フレームに移動しています。スタック ポインターは下方に構築されるため (値が多すぎる場合、ゼロを超えてアンダーフローし、重要なものにオーバーフローする代わりにエラーが発生します)、次に利用可能なスタック フレームの位置は、現在の位置の 1 ワード (4 バイト) 前になります。