RISC-V基础之函数调用(四)非叶函数调用(包含实例)

叶函数是指不调用其他函数,也不改变任何非易失性寄存器的函数2。叶函数通常是一些简单的操作,如数学运算或逻辑判断。叶函数的特点是可以通过模拟返回来展开,即不需要保存或恢复寄存器的状态。

非叶函数是指调用其他函数或改变非易失性寄存器的函数。非叶函数通常是一些复杂的操作,如循环或递归。非叶函数的特点是需要使用静态数据来注释,以便在处理异常时恢复寄存器的状态。

非易失性寄存器是指在断电后仍能保持其内容不变的寄存器。非易失性寄存器通常用于保存一些重要的数据或状态,例如程序计数器、栈指针、返回地址等。

易失性寄存器是指在断电后会丢失其内容的寄存器。易失性寄存器通常用于保存一些临时的数据或操作数,例如通用寄存器、浮点寄存器、向量寄存器等。

非易失性寄存器和易失性寄存器在函数调用时有不同的约定。一般来说,被调用函数需要保护非易失性寄存器的值,即在使用之前将其压入栈中,在返回之前将其弹出栈中。而被调用函数可以自由地使用易失性寄存器,而不需要保存或恢复它们的值。这样可以减少函数调用时的开销和复杂度

函数调用时,需要遵循以下两条规则:

  • 调用者保存规则:在函数调用之前,调用者必须保存任何临时(t0--t6 和 a0--a7)寄存器,这些寄存器在调用后仍然需要。在调用后,它必须在使用它们之前恢复这些寄存器。
  • 被调用者保存规则:在被调用者改变任何保留寄存器(s0--s11 和 ra)之前,它必须保存这些寄存器。在返回之前,它必须恢复这些寄存器。

上图给出一个非叶函数 f1 和一个叶函数 f2 的代码示例,以及它们如何遵循这些规则。非叶函数是指调用其他函数的函数,叶函数是指不调用其他函数的函数。

f1 保持 i 在 s4 和 x 在 s5;f2 保持 r 在 s4。f1 使用了保留寄存器 s4、s5 和 ra,所以它最初将它们压入栈中,以遵循被调用者保存规则。它使用 t3 来保存中间结果 (a--b),这样就不需要为这个计算保留另一个寄存器。

在调用 f2 之前,f1 将 a0 和 a1 保存到栈中,以遵循调用者保存规则,因为这些是非易失性寄存器,f2 可能会改变它们,而 f1 在调用后仍然需要它们。ra 改变了,因为它被 f2 的调用覆盖了。虽然 t3 也是一个非易失性寄存器,f2 可能会覆盖它,但 f1 不再需要 t3,所以不必保存它。

f1 然后将参数传递给 f2 在 a0 中,进行函数调用,并在 a0 中得到结果。f1 然后恢复 a0 和 a1,因为它仍然需要它们。当 f1 完成时,它将返回值放在 a0 中,恢复寄存器 s4、s5、ra 和 sp,并返回。f2 根据被调用者保存规则保存和恢复 s4(和 sp)。

仔细观察后,可能会注意到 f2 没有修改 a1,所以 f1 不需要保存和恢复它。然而,编译器不能总是很容易地确定哪些非易失性寄存器可能在函数调用期间被干扰。因此,一个简单的编译器总是让调用者保存和恢复任何它在调用后需要的非易失性寄存器。一个优化的编译器可以观察到 f2 是一个叶过程,并可以将 r 分配给一个非易失性寄存器,避免了保存和恢复 s4 的需要。下图显示了函数执行期间的栈情况。对于这个例子,栈指针最初从 0xBEF7FF0C 开始。

相关推荐
全球通史7 小时前
[特殊字符] RISC-V实战:从0到100+FPS!进迭时空(Spacemit)开发板YOLOv8部署终极指南
嵌入式硬件·yolo·risc-v
码界奇点1 天前
Linux进程间通信三System V 共享内存完全指南原理系统调用与 C 封装实现
linux·c语言·网络·c++·ux·risc-v
飞凌嵌入式2 天前
【玩转多核异构】T153核心板RISC-V核的实时性应用解析
linux·嵌入式硬件·嵌入式·risc-v
卡奥斯开源社区官方2 天前
NVIDIA CUDA全面支持RISC-V深度解析:技术原理、开发实操与生态红利
risc-v
爱喝矿泉水的猛男2 天前
单周期Risc-V指令拆分与datapath绘制
运维·服务器·risc-v
国科安芯4 天前
FreeRTOS 在 AS32系列RISC-V 架构MCU电机驱动中的应用实践与优化
单片机·嵌入式硬件·安全·架构·压力测试·risc-v·安全性测试
矜辰所致6 天前
沁恒 RISC-V 蓝牙芯片 Flash 分区管理及操作
risc-v·flash·flash读写·ch585·蓝牙 ble
矜辰所致6 天前
沁恒微 RISC-V 蓝牙芯片低功耗测试
低功耗·risc-v·ble 蓝牙·蓝牙低功耗·沁恒微蓝牙
易·木6 天前
阅读 RISC-V 手册
risc-v
矜辰所致11 天前
CH585 高速 USB模拟 CDC串口应用示例
沁恒微·risc-v·usb·cdc串口·usb 模拟串口