assembly - 帧指针的优点是什么?

标签 assembly mips

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

如果我有函数序言,我以前直接做堆栈指针 :

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

在函数结语中:
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

老师说在我们用汇编写函数的时候,使用帧指针对我们人类很有用:
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

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

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

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

最佳答案

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

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

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

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

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

关于assembly - 帧指针的优点是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46797915/

相关文章:

assembly - ARM Cortex A8 基准测试 : can someone help me make sense of these numbers?

gdb - 使用 gdb 检查 eCos mips 目标上的 "non-current"线程

C 到 MIPS 转换 : decoder

MIPS 流水线中的低延迟

assembly - 在 Linux 内核中断处理程序中传递函数参数(从 asm 到 C)

c - Alloca 实现

memory - MIPS 说明 : sw

byte - 在此 MIPS 代码中,哪个字节是从内存中加载的?

c - 如何在汇编中将数组中特定点的值存储到寄存器,反之亦然

assembly - 是否需要为 X64 快速调用叶函数保留 RCX?