当前位置: 首页 > news >正文

RISC-V基础之函数调用(五)函数递归调用及函数参数数量溢出(超出现有寄存器个数)约定(包含实例)

首先先解释一下栈在函数调用中的作用,更详细的部分请参照考研复习之数据结构笔记(五)栈和队列(上)(包含栈的相关内容)_管二狗赶快去工作!的博客-CSDN博客

函数嵌套调用栈的作用是用来保存和恢复函数调用过程中的相关信息,如参数、局部变量、返回地址、上下文等。这些信息可以帮助函数在执行完毕后返回到正确的位置,以及在发生异常时恢复到合理的状态。函数嵌套调用栈的具体结构和操作取决于编译器、操作系统和体系结构的设计,但一般来说,它遵循以下原则:

  • 当一个函数被调用时,它会在栈顶分配一段空间,称为栈帧(stack frame)。栈帧中存放了该函数的参数、局部变量、返回地址、上下文等信息。
  • 当一个函数调用另一个函数时,它会将新的栈帧压入栈顶,形成一个嵌套的结构。这样,每个函数都可以访问自己的栈帧中的信息,而不会影响其他函数的信息。
  • 当一个函数执行完毕后,它会将自己的栈帧弹出栈顶,释放空间。然后,它会根据返回地址跳转回调用者,并将返回值传递给调用者。
  • 当一个函数发生异常时,它会将异常信息保存在栈中,并跳转到异常处理程序。异常处理程序可以根据栈中的信息进行恢复或终止操作。

为了更好地理解函数嵌套调用栈的作用,我们可以看一个简单的例子。假设我们有以下三个函数:

int f1(int a, int b) {int c = a + b;int d = f2(c);return d;
}int f2(int x) {int y = x * x;int z = f3(y);return z;
}int f3(int r) {int s = r - 1;return s;
}

现在我们假设主程序调用了 f1(2, 3)。那么函数嵌套调用栈的变化如下:

  • 主程序在调用 f1(2, 3) 之前,会将参数 a = 2b = 3 压入栈中,并将返回地址(主程序中 f1(2, 3) 的下一条指令)压入栈中。然后跳转到 f1 的起始地址。
  • f1 在执行时,会在栈顶分配一段空间,存放自己的局部变量 cd。然后计算 c = a + b = 5 并保存在栈中。
  • f1 在调用 f2(c) 之前,会将参数 x = c = 5 压入栈中,并将返回地址(f1f2(c) 的下一条指令)压入栈中。然后跳转到 f2 的起始地址。
  • f2 在执行时,会在栈顶分配一段空间,存放自己的局部变量 yz。然后计算 y = x * x = 25 并保存在栈中。
  • f2 在调用 f3(y) 之前,会将参数 r = y = 25 压入栈中,并将返回地址(f2f3(y) 的下一条指令)压入栈中。然后跳转到 f3 的起始地址。
  • f3 在执行时,会在栈顶分配一段空间,存放自己的局部变量 s。然后计算 s = r - 1 = 24 并保存在栈中。
  • f3 在执行完毕后,会将自己的返回值 s = 24 放在 a0 寄存器中,并将自己的栈帧弹出栈顶,释放空间。然后,它会根据返回地址跳转回 f2
  • f2 在接收到 f3 的返回值后,会将其保存在栈中的 z 中。然后,它会将自己的返回值 z = 24 放在 a0 寄存器中,并将自己的栈帧弹出栈顶,释放空间。然后,它会根据返回地址跳转回 f1
  • f1 在接收到 f2 的返回值后,会将其保存在栈中的 d 中。然后,它会将自己的返回值 d = 24 放在 a0 寄存器中,并将自己的栈帧弹出栈顶,释放空间。然后,它会根据返回地址跳转回主程序。
  • 主程序在接收到 f1 的返回值后,会将其保存在某个变量中。然后,它会将栈中的参数 a = 2b = 3 弹出栈顶,释放空间。然后,它会继续执行下一条指令。

递归函数是一种非叶函数,它调用自身。递归函数既是调用者又是被调用者,所以它必须保存和恢复保留和非保留寄存器。

例如,阶乘函数可以写成一个递归函数。回忆一下,阶乘(n) = n × (n – 1) × (n – 2) × ⋯ × 2 × 1。阶乘函数可以递归地写成阶乘(n) = n × 阶乘(n – 1),如下图所示。1 的阶乘就是 1。

 

假设程序从地址 0x8500 开始。根据被调用者保存规则,阶乘是一个非叶函数,必须保存 ra。根据调用者保存规则,阶乘在调用自身后仍然需要 n,所以它必须保存 a0。因此,它在开始时将这两个寄存器压入栈中。然后它检查 n 是否小于等于 1。如果是的话,它将返回值 1 放在 a0 中,恢复栈指针,并返回到调用者。在这种情况下,它不需要恢复 ra,因为它从未被修改过。如果 n 大于 1,函数递归地调用阶乘(n−1)。然后它从栈中恢复 n 和返回地址寄存器 (ra),进行乘法,并返回这个结果。注意,函数巧妙地将 n 恢复到 t1 中,以免覆盖返回值。乘法指令 (mul a0,t1,a0) 将 n (t1) 和返回值 (a0) 相乘,并将结果放在 a0 中,即返回寄存器。

为了清楚起见,我们在函数调用开始时保存寄存器。一个优化的编译器可能会观察到当 n 小于等于 1 时,没有必要保存 a0 和 ra,并且只在函数的 else 部分将寄存器保存到栈上。下图显示了执行阶乘(3) 时的栈情况。

为了说明,我们假设 sp 最初指向 0xFF0(高地址位为 0),如上图(a) 所示。函数创建了一个两字的栈帧来保存 n (a0) 和 ra。在第一次调用时,阶乘将 a0(保存 n = 3)保存在 0xFEC 和 ra 在 0xFE8 中,如图 (b) 所示。函数然后将 n 改变为 2 并递归地调用阶乘(2),使 ra 持有 0x8528。在第二次调用时,它将 a0(保存 n = 2)保存在 0xFE4 和 ra 在 0xFE0 中。这次我们知道 ra 包含 0x8528。函数然后将 n 改变为 1 并递归地调用阶乘(1)。

在第三次调用时,它将 a0(保存 n = 1)保存在 0xFDC 和 ra 在 0xFD8 中。这次 ra 再次包含 0x8528。第三次调用阶乘返回值为 1 的 a0,并在返回到第二次调用之前释放栈帧。第二次调用恢复 n(到 t1)为 2,恢复 ra 到 0x8528(它恰好已经有了这个值),释放栈帧,并返回 a0 = 2 × 1 = 2 给第一次调用。第一次调用恢复 n(到 t1)为 3,恢复 ra,调用者的返回地址,释放栈帧,并返回 a0 = 3 × 2 = 6。图© 显示了递归调用的函数返回时的栈情况。当阶乘返回到调用者时,栈指针在它的原始位置(0xFF0),栈指针以上的栈内容没有改变,并且所有的保留寄存器保持它们的原始值。a0 持有返回值,6。

另外,在函数调用过程中如果一个RISC-V函数需要的参数超过了八个寄存器,即a0到a7,那么它应该按照标准调用约定的规则,将多余的参数通过堆栈(stack)传递。具体来说,调用者(caller)在进行函数调用前,需要将多余的参数按照顺序压入堆栈中,并且在调用后将它们从堆栈中弹出。被调用者(callee)在接收到参数后,需要从堆栈中按照相反的顺序取出多余的参数,并且在返回前将它们放回堆栈中。这样可以保证函数调用前后堆栈的内容和指针不变,以及参数的正确传递。

例如,如果一个函数需要10个整数参数,那么它可以将前八个参数放在寄存器a0到a7中,将后两个参数压入堆栈中。被调用者可以从寄存器a0到a7中直接读取前八个参数,从堆栈中读取后两个参数。在返回前,被调用者需要将后两个参数放回堆栈中。调用者在函数返回后,需要将后两个参数从堆栈中弹出。

图(b) 显示了被调用者堆栈帧的组织。 堆栈帧保存临时、参数和返回地址寄存器(如果由于后续函数调用而需要保存它们),以及函数将修改的任何已保存寄存器。 它还保存局部数组和任何多余的局部变量。 如果被调用者有超过八个参数,它会在调用者的堆栈帧中找到它们。 

 

相关文章:

RISC-V基础之函数调用(五)函数递归调用及函数参数数量溢出(超出现有寄存器个数)约定(包含实例)

首先先解释一下栈在函数调用中的作用,更详细的部分请参照考研复习之数据结构笔记(五)栈和队列(上)(包含栈的相关内容)_管二狗赶快去工作!的博客-CSDN博客 函数嵌套调用栈的作用是用…...

力扣:48. 旋转图像(Python3)

题目: 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 来源:力扣(LeetCode) 链接&…...

HarmonyOS应用开发者基础与高级认证题库——中级篇

系列文章目录 HarmonyOS应用开发者基础与高级认证题库——基础篇 HarmonyOS应用开发者基础与高级认证题库——中级篇 文章目录 系列文章目录前言一、判断二、单选三、多选 前言 今天刚换了台果子手机就收到了华子鸿蒙开发认证邀请(认证链接)&#xff0…...

Python中实现多个列表、字典、元组、集合的连接

目录 目录 前言 一、列表 1、运算符 2、extend()方法 3、解包操作 * 二、字典 1、update()方法 2、解包操作 ** 三、元组 1、 运算符 2、解包操作 * 四、集合 1、union方法 2、| 运算符 3、解包操作 * 五、不同类…...

1005 继续(3n+1)猜想

描述 卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。 当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n3 进行验证的时候,我们需要计算 3、5、8、4、…...

基于图片、无人机、摄像头拍摄进行智能检测功能

根据要求进行无人机拍摄的视频或图片进行智能识别,开发过程需要事项 1、根据图片案例进行标记,进行模型训练 2、视频模型训练 开发语言为python 根据需求功能进行测试结果如下 根据车辆识别标记进行的测试结果截图 测经过查看视频 8月1日...

Boost开发指南-4.2ignore_unused

ignore_unused 编写代码的过程中有时会出现一些暂时用不到但又必须保留的变量,GCC等编译器会对此发出警告,使用-Wunused可以关闭这些警告消息,不过这也有可能导致潜在的隐患。古老的办法是使用(void)var的形式来“使用”一下变量&#xff0c…...

【Mybatis】XML映射文件

目录 11.3XML映射文件 1.select 2.insert、update、delete 3.Sql 4.parameters(参数) 5.resultMap 6.resultMap 使用示例 (1)在先前创建的数据库stu中创建表student 2,并插入若干条数据,代码如下: (2)创建工程mybatis_ResultMap_demo。 (…...

11.2【MyBatis】主配置文件

目录 11.2【MyBatis】主配置文件 1.properties(属性) 2.settings(设置) 3.typeAliases(别名) 4.typeHandlers类型处理器 5.objectFactory 对象工厂 6.plugins(插件) 7.environments (配置环境) 8.mappers (映射器) 11.2【MyBatis】主配置文件 MyBatis的 …...

linuxARM裸机学习笔记(2)----汇编LED灯实验

MX6ULL 的 IO IO的复用功能 这里的只使用了低五位,用来配置io口,其中bit0~bit3(MUX_MODE)就是设置 GPIO1_IO00 的复用功能的,GPIO1_IO00 一共可以复用为 9种功能 IO,分别对应 ALT0~ALT8。每种对应了不同的功能 io的属性配置 HY…...

用C语言实现插入排序算法

1.设计思路 用插入排序对长度为n的待排序数组A进行排序的伪代码(在代码中,A中元素的数目n用A.length来表示)。 伪代码如下: INSERTION-SORT(A) for j2 to A.length:keyA[j] //将A[j]插入已排序序列A[1..j-1]ij-1while i>0…...

2023 电赛E题--可能会出现的问题以及解决方法

2023年电赛E题报告模板(K210版)--可直接使用 本文链接:2023年电赛E题报告模板(K210版)--可直接使用_皓悦编程记的博客-CSDN博客 解决激光笔在黑色区域无法识别 本文链接: 2023 电赛 E 题 激光笔识别有误-…...

Demystifying Prompts in Language Models via Perplexity Estimation

Demystifying Prompts in Language Models via Perplexity Estimation 原文链接 Gonen H, Iyer S, Blevins T, et al. Demystifying prompts in language models via perplexity estimation[J]. arXiv preprint arXiv:2212.04037, 2022. 简单来说就是作者通过在不同LLM和不同…...

WEB集群——http、tomcat

1. 简述静态网页和动态网页的区别。 2. 简述 Webl.0 和 Web2.0 的区别。 3. 安装tomcat8,配置服务启动脚本,部署jpress应用。 1. 简述静态网页和动态网页的区别。 1)、静态网页 (1)、什么是静态网页 请求响应信息&…...

Socks5代理:网络安全与爬虫之利器

一、Socks5代理:简介与工作原理 Socks5代理,全称为Socket Secure 5代理,是一种允许用户通过代理服务器进行网络连接的技术。它是Socks协议的最新版本,在网络安全和数据传输方面有着显著的优势。 Socks5代理与其他代理的不同之处在…...

如何兼容低版本浏览器

如何兼容低版本浏览器 分为三个部分来说 HTML 低版本浏览器无法识别新增的HTML5元素,如果要兼容这部分浏览器,需要做以下处理: 对于非可替换元素,比如article、section、header、footer等,这种元素虽然低版本浏览器不识…...

【雕爷学编程】MicroPython动手做(39)——机器视觉之图像基础2

MixPY——让爱(AI)触手可及 MixPY布局 主控芯片:K210(64位双核带硬件FPU和卷积加速器的 RISC-V CPU) 显示屏:LCD_2.8寸 320*240分辨率,支持电阻触摸 摄像头:OV2640,200W像素 扬声器&#…...

gitlab搭建

回到目录 GitLab 是一个用于仓库管理系统的开源项目,使用 Git 作为代码管理工具,并在此基础上搭建起来的 Web 服务。 Gitlab 是被广泛使用的基于 git 的开源代码管理平台, 基于 Ruby on Rails 构建, 主要针对软件开发过程中产生的代码和文档进行管理,…...

JMeter 的使用

文章目录 1. JMeter下载2. JMeter的使用2.1 JMeter中文设置2.2 JMeter的使用2.2.1 创建线程组2.2.2 HTTP请求2.2.3 监听器 1. JMeter下载 官网地址 https://jmeter.apache.org/download_jmeter.cgi https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.6.2.zip 下载解…...

Java语言 Iterator 如何装换成 List

迭代器如何逆向转换成List集合 在 Java 中,迭代器(Iterator)是一种用于遍历集合中元素的对象,它提供了一种简单而一致的方式来访问集合中的元素,而不需要暴露集合内部的结构。如果我们需要将一个迭代器逆向转换成 Lis…...

当你的数据库学习遇到瓶颈时,Chinook数据库如何成为你的跨平台解决方案?

当你的数据库学习遇到瓶颈时,Chinook数据库如何成为你的跨平台解决方案? 【免费下载链接】chinook-database Sample database for SQL Server, Oracle, MySQL, PostgreSQL, SQLite, DB2 项目地址: https://gitcode.com/gh_mirrors/ch/chinook-database…...

终极指南:如何快速解决RevokeMsgPatcher微信3.9.10.19版本路径兼容性问题

终极指南:如何快速解决RevokeMsgPatcher微信3.9.10.19版本路径兼容性问题 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: …...

iTorrent:iPhone种子下载的终极解决方案 - 如何在iOS上轻松管理BitTorrent文件

iTorrent:iPhone种子下载的终极解决方案 - 如何在iOS上轻松管理BitTorrent文件 【免费下载链接】iTorrent Torrent client for iOS 16 项目地址: https://gitcode.com/gh_mirrors/it/iTorrent 想在iPhone上轻松下载和管理种子文件吗?iTorrent为你…...

3分钟快速上手:WorkshopDL终极跨平台Steam创意工坊下载器完全指南

3分钟快速上手:WorkshopDL终极跨平台Steam创意工坊下载器完全指南 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否拥有Epic或GOG平台的游戏,却眼馋…...

Windows终极解决方案:3步快速配置Coolapk-Lite UWP客户端,告别安卓模拟器

Windows终极解决方案:3步快速配置Coolapk-Lite UWP客户端,告别安卓模拟器 【免费下载链接】Coolapk-Lite 一个基于 UWP 平台的第三方酷安客户端精简版 项目地址: https://gitcode.com/gh_mirrors/co/Coolapk-Lite 还在为在Windows电脑上访问酷安社…...

LLaMA-Factory实战:基于Qwen2.5-VL-7B-Instruct的印章识别微调指南

1. 环境准备与基础配置 在开始微调Qwen2.5-VL-7B-Instruct模型之前,我们需要搭建好开发环境。这里推荐使用Docker容器来保证环境的一致性,避免因为系统差异导致的问题。我实测过在Ubuntu 20.04和22.04系统上都能稳定运行,下面分享具体配置步骤…...

GLM-4.1V-9B-Base效果实录:从模糊证件照中准确提取姓名与关键字段

GLM-4.1V-9B-Base效果实录:从模糊证件照中准确提取姓名与关键字段 1. 视觉多模态模型的惊艳表现 在现实工作中,我们经常需要处理各种证件照片,但低分辨率、模糊或倾斜的证件照往往让人头疼。传统OCR技术在这些场景下表现不佳,而…...

10个Plover实用技巧:从基础操作到高级自定义配置

10个Plover实用技巧:从基础操作到高级自定义配置 【免费下载链接】plover Open source stenotype engine 项目地址: https://gitcode.com/gh_mirrors/pl/plover Plover是一款开源速记引擎,能够帮助用户通过速记键盘实现高效输入。本文将分享10个实…...

如何快速掌握FanControl:5分钟实现智能风扇控制与中文界面

如何快速掌握FanControl:5分钟实现智能风扇控制与中文界面 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trendin…...

WeChatExporter:3步解锁iOS微信聊天记录,让数字记忆不再丢失

WeChatExporter:3步解锁iOS微信聊天记录,让数字记忆不再丢失 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 你是否曾因手机存储空间不足而被迫删…...