在编写汇编代码时,我是否可以直接使用堆栈指针访问函数参数和局部变量,而无需将基指针保存到堆栈中并在被调用函数中设置新的基指针?
答案 0 :(得分:2)
在32位(IA-32)和64位代码(x86-64)中,在16位代码(8086 ... 80286)中没有。 sp
无法以任何方式用于解决,esp
和rsp
可以。{/ p>
Wikipedia has a useful list of possible x86 and x86 addressing modes
仅在16位代码中使用bp
或其他可用于寻址的寄存器(bx
,si
,di
)。
答案 1 :(得分:2)
是的,在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.
答案 2 :(得分:1)
如果您使用ESP或RSP,而不是SP,则可以这样做,因为没有SP相对内存寻址,只有ESP相对和RSP相对。