0

在编写汇编代码时,是否可以直接使用堆栈指针访问函数参数和局部变量,而无需将基指针保存到堆栈中并在被调用函数中设置新的基指针?

4

3 回答 3

2

在 32 位 (IA-32) 和 64 位代码 (x86-64) 中是,在 16 位代码 (8086 ... 80286) 中没有。sp不能以任何方式用于寻址,esp并且rsp可以。

维基百科有一个有用的 x86 和 x86 寻址模式列表

仅在 16 位代码中需要使用bp或其他可用于寻址 ( bx, si, ) 的寄存器。di

于 2013-01-30T12:10:24.477 回答
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.
于 2013-02-03T23:03:41.783 回答
1

如果您使用 ESP 或 RSP,但不是 SP,您可以这样做,因为没有 SP 相对内存寻址,只有 ESP 相对和 RSP 相对。

于 2013-01-30T12:14:11.980 回答