本文目标
下图列举了 RISC-V 处理器中的通用暂存器:
针对上图,笔者针对一些可能会有疑问的点进行补充:
x0 暂存器
x0 暂存器的数值为 0 且无法更动,我们可以利用他做到类似 mov 的作用:
add a0 a1, x0 # a0 = a1
Return Address
Return Address 存放函式执行结束时返回的位置,假设,有两个函式 a, b :
main() -> a()
a() -> b()
因为 main()
呼叫了函式 a()
,在跳进函式 a()
执行前,main()
会将 ra
暂存器的值放到 Stack 上。
此时,如果函式 a()
又呼叫了函式 b()
,在呼叫之前我们会将函式 a()
的 return address 储存到 Stack,避免 ra 暂存器被函式 b()
复写後无法返回到 main()
继续执行。由此可知,ra
由呼叫者维护暂存器的状态,这类特性的暂存器都是 Caller save。
在这边如果不考虑 Stack pointer,Stack 内部看起来会是:
+------------------------------+
| Data stored by function b |
+------------------------------+
| Return Address of function a |
+------------------------------+
| Return Address of main |
--+------------------------------+--
Stack pointer
然而,每个 Process 都会有属於自己的区域变数,这些变数同样会被存放在 Stack 中,Stack pointer 会指向 Stack 中属於此 Process 的位址。
不过,这部分与 ra
会些不同,sp
暂存器被定义为 Callee save,当被呼叫的函式修改 sp
暂存器的内容之前,必须先将内容保存下来,并在函式返回前恢复原本的值。
如果以 main()
呼叫 function a()
来看,流程如下:
main() 将当前 ra 的值放到 stack -> 进入 function a() -> 将 sp 的值存放到 stack -> 移动 sp 的位址 (Scope of function a) -> 一些运算 -> 返回到 main 之前恢复 sp 的值 -> 跳回 main() -> 恢复 main() 的 ra
Function args: a0-a7 (x10-x17)
a0-a7 共 8 个暂存器可供我们用於存取函式的参数值,当我们呼叫函式时,函式的参数会依序的存放到这些暂存器中。
Return values: a0-a1
a0, a1 暂存器除了会被当作 args 使用,当函式需要有 return value 时,我们可以将 return value 存放至 a0 与 a1 暂存器,供其他函式取得返回值。
本篇文章介绍了 RISC-V 之中常用的暂存器,包含了:
以上两点其实就是 RISC-V 的 Calling convention (呼叫惯例),这些规范在编译器的实作上都能看到,理解它更有助於嵌入式的系统软件开发。
本系列文之後也会置於个人网站 终於要来好好介绍一下甚麽是Keycloak了~ 收先先来看一下Key...
上一篇有介绍压缩的一些套件了 不过有时候 我们在开发的时候 有时压缩 有时不压缩 那要怎麽解决 所以...
为什麽要做测试? 今天在外面餐厅吃饭,厨师在出菜前会先试吃看看味道对不对;一台咖啡机,在出厂前也会经...
开始绘图吧! 有了基础场景後,就可以开始画图了,首先使用new建构出PIXI.Graphics()图...
今天大概会聊到的范围 viewModel in Compose 今天的主题很单纯:如果专案中有使用...