帧指针的优点是什么?

NoI*_*Guy 5 assembly mips

我们正在学习 MIPS 汇编器(我想这个问题可以适用于一般的汇编),老师向我们介绍了frame pointer

如果我有一个函数序言,我曾经直接做堆栈指针

addiu $sp, $sp, -8   ; alloc 2 words in the stack
sw $s0, 4($sp)       ; save caller function $s0 value in the stack
sw $ra, ($sp)        ; save the return address for the callee function
Run Code Online (Sandbox Code Playgroud)

在函数结语中:

move $v0, $0         ; set 0 as return value
lw $s0, 4($sp)       ; pick up caller $s0 value from the stack
lw $ra, ($sp)        ; pick up return address to return to the caller
addiu $sp, $sp, 8    ; dealloc the stack words I used
jr $ra               ; return back to caller
Run Code Online (Sandbox Code Playgroud)

老师说在我们用汇编写函数的时候,使用帧指针对我们人类很有用:

addiu $sp, $sp, -12  ; alloc 3 words in the stack
sw $fp, 8($sp)       ; save caller frame pointer in the stack
addiu $fp, $sp, 8    ; set $fp to the uppermost address of the activation frame
sw $ra, -4($fp)      ; saving like the first example, but relative 
sw $s0, -8($fp)      ; to the frame pointer
Run Code Online (Sandbox Code Playgroud)

老师也说有时候栈指针继续分配其他空间,在函数内引用激活帧比较困难,因为我们需要注意。使用帧指针,我们将有一个指向激活帧的静态指针。

是的,但是我是否需要在函数内使用激活,因为它只包含调用者函数的保存数据?

我认为这只会让事情更难实施。是否有一个实际的例子,其中帧指针对程序员来说是一个巨大的优势?

Ros*_*dge 8

当在堆栈上动态分配可变数量的空间时,您绝对只需要一个帧指针。使用可变长度数组和/或allocaC 语言的函数是需要帧指针的函数示例。由于函数使用的堆栈量是可变的,因此您不能使用堆栈指针的常量偏移量来访问变量,并且您需要一种方法在函数返回时撤消可变长度分配。使用帧指针可以解决这两个问题。您可以使用它使用常量偏移来寻址堆栈变量,并将堆栈指针恢复到函数开始时的值。

在 MIPS 上,如果总堆栈分配超过 32k,则在仅使用固定大小堆栈分配的函数中使用帧指针作为优化也是有意义的。MIPS 支持的有限寻址模式仅允许相对于堆栈指针或任何其他寄存器的 16 位符号扩展偏移。由于堆栈指针指向堆栈底部,因此堆栈指针只能使用非负偏移量,因此单条指令只能寻址堆栈上的 32k。通过使用帧指针并将其指向堆栈帧的中间(而不是帧的顶部),它可以用于在单个指令中寻址最多 64k 的堆栈。

否则,使用帧指针只会有利于程序员,而不是程序。如果程序中的所有函数都使用带有帧指针的标准堆栈帧,则帧指针和存储在堆栈中的所有保存的帧指针值形成堆栈帧的链表。在调试时可以轻松地遍历此链表以创建函数调用的引用。但是,使用合适的现代调试器,还可以将元数据(展开信息)嵌入到可执行文件中,即使不使用帧指针,调试器也可以使用这些元数据来遍历堆栈帧。现代编译器可以自动执行此操作,但在汇编语言中,包含所有必要的额外指令以使其工作可能会非常痛苦。

如果堆栈指针可以在函数期间通过固定大小的分配和释放来多次更改,那么在程序中的任何给定点跟踪变量相对于堆栈指针的位置可能会很痛苦。虽然它在任何给定位置始终处于固定偏移处,但会根据位置而变化。确定偏移量可能很棘手并且容易出错。使用帧指针将为每个变量提供一个相对于帧指针的偏移量,该偏移量永远不会改变,因为帧指针值不会改变。

请注意,如果您觉得需要使用帧指针,因为最后两个原因之一,您必须首先考虑为什么要在汇编中进行编程。在这些情况下,现代编译器不需要使用帧指针,因此会生成更好的代码。