RISCV简单介绍
寄存器
指令格式
常用指令
源文件
#include <stdio.h>
int fib(int n) {
if (n <= 2)
return 1;
return fib(n - 1) + fib(n - 2);
}
int main() { fib(3); }
汇编代码
0000000000000628 <fib>:
628: 7179 addi sp,sp,-48 //栈指针-48
62a: f406 sd ra,40(sp) //保存函数返回地址
62c: f022 sd s0,32(sp) //保存 保存寄存器的值,这些值在当前函数返回后还会被之前的函数接着使用
62e: ec26 sd s1,24(sp) //同上
630: 1800 addi s0,sp,48 //栈指针+48赋值给s0
632: 87aa mv a5,a0 //伪指令 复制寄存器的值 a5=a0,a0为传递来的参数
634: fcf42e23 sw a5,-36(s0) //*(sp-36)=a5
638: fdc42783 lw a5,-36(s0) //a5=*(sp-36)
63c: 0007871b sext.w a4,a5 //将a5符号扩展 并传递给a4
640: 4789 li a5,2 //伪指令 load立即数2
642: 00e7c463 blt a5,a4,64a <fib+0x22>//分支指令 如果a4<a5 则PC寄存器加上立即数,跳转到fib+0x22
646: 4785 li a5,1
648: a025 j 670 <fib+0x48>//跳转
64a: fdc42783 lw a5,-36(s0) // 即传递进来的参数赋值给a5
64e: 37fd addiw a5,a5,-1 //a5加上立即数-1
650: 2781 sext.w a5,a5 //符号扩展
652: 853e mv a0,a5 //复制寄存器的值
654: fd5ff0ef jal ra,628 <fib>//跳转 即调用 f(n-1)
658: 87aa mv a5,a0 //函数调用返回值保存到a5
65a: 84be mv s1,a5 //复制寄存器
65c: fdc42783 lw a5,-36(s0)
660: 37f9 addiw a5,a5,-2
662: 2781 sext.w a5,a5
664: 853e mv a0,a5
666: fc3ff0ef jal ra,628 <fib>
66a: 87aa mv a5,a0 // 65c-66a 同 64a-658
66c: 9fa5 addw a5,a5,s1// a5=a5+s1 f(n-1)+f(n-2)
66e: 2781 sext.w a5,a5
670: 853e mv a0,a5
672: 70a2 ld ra,40(sp) // 恢复成调用之前的状态
674: 7402 ld s0,32(sp)
676: 64e2 ld s1,24(sp)
678: 6145 addi sp,sp,48
67a: 8082 ret //伪指令 PC=ra
000000000000067c <main>:
67c: 1141 addi sp,sp,-16 //将栈指针-16
67e: e406 sd ra,8(sp) //保存函数返回地址
680: e022 sd s0,0(sp) // 保存寄存器由被调用者保存,保存main函数被调用之前的保存寄存器的值
682: 0800 addi s0,sp,16//栈指针+16赋值给s0
684: 450d li a0,3 //a系列寄存器用户传递函数参数或者传递函数返回值
686: fa3ff0ef jal ra,628 <fib>//跳转指令 将返回地址(68a)保存在ra寄存器中
68a: 4781 li a5,0 //伪指令 load立即数
68c: 853e mv a0,a5 //伪指令 复制寄存器的值
68e: 60a2 ld ra,8(sp) //load ra=*(sp+8) 函数调用返回值
690: 6402 ld s0,0(sp) //s0= *(sp) 恢复之前保存的s0的值
692: 0141 addi sp,sp,16 //栈指针+16
694: 8082 ret //函数返回 伪指令,实际是jalr 返回地址在机器指令指定的寄存器中