帧指针有什么优点?

2023-11-21

我们正在学习 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

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

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

我认为这只会让事情变得更难实施。有没有一个真正的实际例子表明帧指针对程序员来说是一个很大的优势?


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

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

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

帧指针有什么优点? 的相关文章

  • 从 DX:AX 寄存器转移到单个 32 位寄存器

    我在添加 16 位乘法的乘积时遇到问题 我想将一年 例如 2015 年 乘以 365 为此 我 mov dx 0 to clear the register mov ax cx cx holds the year such as 2015
  • 嵌入式系统:使用汇编语言时的内存布局

    根据我的理解 嵌入式系统运行机器代码 有多种方法可以生成此代码 一种是用 C 等高级语言编写程序 然后使用编译器获得这样的代码 另一种方法是用汇编语言为该嵌入式系统编写指令 并使用汇编器将其转换为机器代码 现在我们得到了加载到系统并执行的机
  • 裸机交叉编译器输入

    裸机交叉编译器的输入限制是什么 比如它不编译带有指针或 malloc 的程序 或者任何需要比底层硬件更多的东西 以及如何才能找到这些限制 我还想问 我为目标 mips 构建了一个交叉编译器 我需要使用这个交叉编译器创建一个 mips 可执行
  • 为什么前向引用 ADR 指令在 Thumb 代码中以偶数偏移进行汇编?

    To bx对于 Thumb 函数 需要设置地址的最低有效位 GNU 作为文档states https sourceware org binutils docs as ARM Opcodes html当地址是从一个生成时这是如何工作的adr伪
  • movsbl指令的作用是什么? [复制]

    这个问题在这里已经有答案了 我在网上搜索过 但找不到明确的示例来理解该指令的作用 因此 如果有人可以举一个例子 这对我来说将会非常有帮助 用符号从字节扩展到长字移动 在Intel语法中 该指令的助记符是MOVSX 当变量类型为 C 时 C
  • INT 13h 无法读取超出特定扇区的数据

    我正在为我的操作系统编写内核 在将磁盘扇区加载到内存时遇到问题 以下是从磁盘加载扇区的函数代码部分 mov ax 0x3000 mov es ax mov ax 0x0201 mov bx word ptr bp 6 bx 0x000 0x
  • 如何在 AVX/AVX2 中递增向量

    我想使用内在函数来增加 SIMD 向量的元素 最简单的方法似乎是为每个元素加 1 如下所示 note vec inc之前已设置为1 vec mm256 add epi16 vec vec inc 但是是否有任何特殊指令来增加向量 类似于in
  • 如何使 gcc 为 -fpatchable-function-entry 发出多字节 NOP?

    gcc确实有能力使用多字节用于对齐循环和函数的 NOP 然而当我尝试 fpatchable function entry option https gcc gnu org onlinedocs gcc Instrumentation Opt
  • 内核模块未加载(但 insmod 返回 0)

    我必须向现有设备 mips arch 添加一些功能 我已经尝试了几个 SDK 目前我取得了一些进展 但是 insmod 返回 0 成功 并且 lsmod 显示它们 但是 printk 和 create proc entry 都不起作用 但我
  • Linux Shellcode“你好,世界!”

    我有以下可用的 NASM 代码 global start section text start mov eax 0x4 mov ebx 0x1 mov ecx message mov edx 0xF int 0x80 mov eax 0x1
  • 优化算术编码器

    我正在优化名为的 C 库的编码步骤PackJPG http www elektronik htw aalen de packjpg 我使用 Intel VTune 对代码进行了分析 发现当前的瓶颈是 PackJPG 使用的算术编码器中的以下
  • 英特尔 JCC 勘误表 - 用于缓解的前缀有什么影响?

    Intel 推荐 https www intel com content dam support us en documents processors mitigations jump conditional code erratum pd
  • 有哪些 x86 指令会对 ESP 产生副作用?

    我知道call and ret将修改的值esp然后push and pop有很多变体 但是还有其他指令会影响堆栈指针吗 The following instructions modify the stack pointer as an im
  • /usr/bin/as:无法识别的选项“-EL”

    因此 在为我的1plus手机编译android内核时 经过3天的多次尝试 我放弃了并尝试在这里询问是否有人以前遇到过这个问题 这个错误对我来说有点模糊 但我觉得问题来自于我最近对 GNU Linux 发行版 Gentoo 的更改 它在不应该
  • 如何使用 LOCK ASM 前缀来读取值?

    我知道如何使用 LOCK 来线程安全地递增一个值 lock inc J 但是如何以线程安全的方式读取 J 或任何值 LOCK 前缀不能与 mov 一起使用 如果我执行以下操作 xor eax eax lock add eax J mov J
  • 如何在 Linux 中制作一个将文件转换为大写的 x86 汇编程序?

    我找到了一个名为 ProgrammingGroundUp 1 0 booksize pdf 的 pdf 文件 其中一个项目是制作一个汇编程序 该程序接收文件并将其转换为大写 section data CONSTANTS system cal
  • 了解带有 pc 偏移的 Cortex-M 组件 LDR

    我正在查看这段 C 代码的反汇编代码 define GPIO PORTF DATA R volatile unsigned long 0x400253FC int main void Initialization code while 1
  • 0 和双字 0 有什么区别?

    正如问题所述 有什么区别 例如 mov eax 0 and mov eax dword 0 我一直在使用 cmp 语句 但我无法理解其中的区别 一个是地址 另一个是数值 如前所述 MOV 指令没有区别 对于 CMP 您将有以下区别 qwor
  • 为什么每次在 GDB 中构建和反汇编函数时都会得到相同的地址?

    每次反汇编函数时 为什么总是得到相同的指令地址和常量地址 例如 执行以下命令后 gcc o hello hello c ggdb gdb hello gdb disassemble main 转储代码将是 当我退出 gdb 并重新反汇编 m
  • 两个 16 位数字相乘 - 为什么结果是 32 位长? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如果我将两个 16 位数字相乘 结果将是 32 位长 但为什么会这样呢 对此有何明确解释 为了我的正确理解 其计算方法是 n 位数字乘以

随机推荐

  • 无论设置是否正确,PHP 连接都会在大文件上传时重置

    我遇到了一个非常常见的问题 似乎找到的所有可用解决方案都不起作用 我们有一个接收大量流量的 LAMP 服务器 使用此服务器 我们执行定期文件提交上传 在小文件上传时 它工作得很好 对于大约 4 5MB 的文件 此提交上传会间歇性失败 有时有
  • 带有 PhoneGap 的 Google+ 登录按钮

    我们如何将 JS Google 登录按钮与 Phonegap 一起使用 专门针对iOS 我已经发现本文关于使用phonegap和childbrowser插件进行oauth 但是我不确定该方法是否适用于Google 登录按钮 有任何想法吗 G
  • 在 SQLAlchemy 中映射大量相似的表

    我有许多 2000 个位置的时间序列数据 每个时间序列都有数百万行 我想将它们存储在 Postgres 数据库中 我当前的方法是为每个位置时间序列建立一个表 以及一个存储每个位置信息 坐标 海拔等 的元表 我正在使用 Python SQLA
  • 使用什么转换属性进行变换?

    我不确定这是否是正确的方法 但我想旋转一个元素 而且我知道transform rotate 90deg transition property all会起作用 但我不想过渡all的转变 What transition property我应该
  • 我的应用程序的 Facebook 故事:无法生成故事

    在我的 Facebook 应用程序的 Open Graph 仪表板中 在使用标准对象创建自定义或故事后 我的故事出现错误 显示 无法生成故事 因此 在 facebookdeveloper apps myapp story openGraph
  • 当解决方案具有多个 Web 应用程序时,TFS 2010 + MSDeploy

    我有两个解决方案 SolutionA sln WebApplication1 csproj SolutionB sln WebApplication1 csproj WebApplication2 csproj 我还有两个 TFS 2010
  • 以编程方式在表变量中设置身份种子

    我需要创建一个带有标识种子的表变量 该标识种子以另一个表中字段的最大值开头 我试过这个 DECLARE IdentitySeed int SET IdentitySeed SELECT MAX HHRecId 1 FROM xxx DECL
  • 推送通知代码执行(强制退出应用程序)

    我想知道像 Whatsapp 这样的应用程序如何能够向消息的发件人提供送达收据 双绿色支票 我发现 即使您强制退出 Whatsapp 使用应用程序任务切换器并将应用程序滑开 发件人仍然会在手机收到推送通知时收到送达收据 双绿色勾号 显然 他
  • 是否可以从 JavaDoc 创建 Java 类?

    问题是 目前我的团队为一家供应商工作 该供应商为我们提供了他们库中的大量 JavaDoc 规范 但没有提供带有存根或实现的 jar 文件 我们已经与他们交谈过 但他们只会在 2 到 3 周内提供 jar 文件 我不想等到这个时候才开始我们的
  • SQL:从全名字段中解析名字、中间名和姓氏

    如何使用 SQL 从全名字段中解析名字 中间名和姓氏 我需要尝试匹配与全名不直接匹配的名称 我希望能够将全名字段分解为名字 中间名和姓氏 数据不包含任何前缀或后缀 中间名是可选的 数据格式为 First Middle Last 我对一些实用
  • 如何在项目中导入Angular Material?

    我已经安装了 Angular Material Design 现在我尝试将其添加到app module ts file import MaterialModule from angular material 我应该在部分中确定什么 impo
  • 从 websocket 监听器发出全局事件

    我想为一个项目做出贡献 它是用 Vue 编写的 而我是 Vue 的初学者 我有两个组件 Setup and MainApp 两者都需要根据来自 websocket 的不同消息来更新某些状态 有些 websocket 消息会影响前者 有些则影
  • 如何获取实际的监视器名称?如分辨率对话框中所示

    我正在尝试获取系统上监视器的友好名称 我正在使用 C 我努力了Screen 这只是给了我 DisplayXX 我也尝试过Win32 DesktopMonitor and EnumDisplayDevices 它们都给了我以下的变体 Disp
  • pycharm 和子进程 - 在控制台中有效的内容在 Pycharm 中无效

    Pycharm 的解释器似乎已经停止理解我的一些控制台命令 它不断识别默认的 shell 命令 但不识别已安装的实用程序 例如 subprocess模块理解touch命令但不理解heroku命令 有趣的是 当我使用相同的解释器 来自相同的
  • 如何获取乌龟的位置?

    如何在Python中找到乌龟的坐标 例如 如果乌龟位于 200 300 我如何检索该位置 如Python文档所示 turtle pos 以 2D 向量形式返回海龟的当前位置 x y
  • 拼写错误的 Ace 编辑器选项

    我已经为 PHP 实现了 Ace 编辑器设置 工作正常 但是当我尝试使用 Ace 的 API 设置其他选项时 我在控制台中收到警告 这是用于初始化编辑器并尝试设置选项的代码 ace require ace ext language tool
  • 按因子计算组的平均值

    有没有办法可以改进或更简单地做到这一点 means by lt function data INDEX b lt by data INDEX function d apply d 2 mean return structure t matr
  • 在锁定的 Windows 10 计算机上的后台进程中将文本放入剪贴板

    我正在构建一个进程 到目前为止 我已在 Net Framework 4 7 2 上尝试过 VBA Python 和 C 该进程需要将一些字符串放入 Windows 10 计算机锁定屏幕后面的剪贴板上 为了测试 我将其减少到只有两个命令 伪代
  • 如何在 SQL Server 上执行 SQL 脚本期间显示某些内容?

    例如 我有一个数据库升级脚本 用于向数据库表添加列 它看起来有点像这样 IF NOT Exists SELECT FROM SysColumns sc SysObjects so WHERE sc Name dealer number AN
  • 帧指针有什么优点?

    我们正在学习 MIPS 汇编器 我想这个问题可以适用于一般的汇编 老师向我们介绍了帧指针 如果我有一个函数序言 我曾经直接执行堆栈指针 addiu sp sp 8 alloc 2 words in the stack sw s0 4 sp