さて、スタックはどのように機能しますか?たとえば、命令:
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 バイト) 前になります。