アセンブリ コードのコーディング中に、ベース ポインターをスタックに保存したり、呼び出された関数に新しいベース ポインターを設定したりせずに、スタック ポインターを直接使用して関数パラメーターとローカル変数にアクセスできますか?
3 に答える
はい、32ビットと64ビットのアセンブリでは、それぞれESPとRSPでスタックポインタを使用してローカル変数にアクセスできます。変数にアクセスするためにベーススタックポインタを使用する理由は、プッシュまたはポップで位置を変更する可能性があるスタックポインタに対して、常に一定の位置にあるためです。これにより、プッシュとポップの回数を追跡し、それに応じて変数の場所を調整できます。例としてこれを見てください:(これはx64です)
sub rsp, 16 ; Align stack
mov DWORD PTR[rsp], 4
mov DWORD PTR[rsp + 4], 20
mov QWORD PTR[rsp + 8], 175
push 25 ; Push 25 to the stack.
push 50 ; Push 8 to the stack.
...
これで、コードの後半で、最初にスタックに配置した変数にアクセスしたい場合、pushステートメントのためにそれらの場所が変更されました。pushステートメントは次と同等です。
sub rsp, 8
mov QWORD PTR[rsp], 45
スタックに配置したときに変数にアクセスしようとすると、間違った番号が返されます。
mov rax, QWORD PTR[rsp + 8] ; This is not 175, since you did two pushes
; and moved the stack pointer back another 16 bytes.
; You will get 25 as the answer.
次に、実行したプッシュの数を手動で追跡し、それらにアクセスするために変数の場所を調整する必要があります。プロジェクトが大きくなると、これがどの程度の問題を引き起こすかがわかります。
これで、スタックベースポインタを使用して変数にアクセスすると、その場所は一定になり、いつでも同じ場所で変数にアクセスできます(ベースポインタ自体を変更しない限り)
push rbp ; Save the old value of RBP.
mov rbp, rsp
sub rsp, 16 ; Align stack
mov DWORD PTR[rbp - 4], 4
mov DWORD PTR[rbp - 8], 20
mov QWORD PTR[rbp - 16], 175
push 25 ; Push 25 to the stack.
push 50 ; Push 8 to the stack.
...
mov eax, DWORD PTR[rbp - 8] ; This will give you 20 because the
; stack base pointer's location is constant to
; the variables in the stack. The push statements
; only affect the stack pointers location, not the
; base pointer.
...
mov rsp, rbp
pop rbp ; After you pop the previous pushed values.
32 ビット (IA-32) および 64 ビット コード (x86-64) でははい、16 ビット コード (8086 ... 80286) ではいいえ。いかなる方法でsp
もアドレス指定には使用できません。esp
rsp
ウィキペディアには、可能な x86 および x86 アドレッシング モードの便利なリストがあります。
またはアドレス指定に使用bp
できるその他のレジスタ ( bx
、si
、di
) の使用は、16 ビット コードでのみ必要です。
You can do that if you use ESP or RSP, but not SP because there's no SP-relative memory addressing, only ESP-relative and RSP-relative.