RISC-V ABI约定

描述

本文转自公众号,欢迎关注

RISC-V ABI约定 (qq.com)

  • 一.C数据类型和对齐
  • 二.RVG调用约定
  • 三.Soft-Float调用约定
  • 四.总结
  • 使用编译器生成汇编代码分析调用过程
  • 五.参考

一.C数据类型和对齐

所有数据保持自然对齐。

ILP32,LP64

C type Description Bytes in RV32 Bytes in RV64
char/unsigned char 8-bit unsigned integer,zero-extended 1 1
signed char 8-bit signed integer,sign-extended
short 16-bit signed integer,sign-extended 2 2
unsigned short 16-bit unsigned integer,zeroextended
int int都是32位 4 4
long 指针和long和整数寄存器一样宽 4 8
long long long long都是64位 8 8
void * 指针和long和整数寄存器一样宽 4 8
float 32-bit IEEE 754-2008 4 4
double 64-bit IEEE 754-2008 8 8
long double 128-bit IEEE floating-point
IEEE floating-point 16 16

在RV64中,32位类型不管是int还是unsigned都是符号扩展到64位。

二.RVG调用约定

  1. a0-a7,fa0-fa7:用于函数传递参数,其中0-1用于返回值,a表示arguments

都是调用者负责保存,因为是传参肯定是在函数调用前就要准备好,所部不可能是被调用者去负责保存。

  1. 如果函数参数为结构体的字段,每一个都是指针对齐的,则参数寄存器是结构体前面8个指针字pointer-words的影子shadow

如果是小于8个的浮点值,则使用fai传递;小于8个的整数则使用ai传递。

如果浮点参数是联合体unions的字段,或者结构体的数组字段,则使用整数寄存器传递。

另外可变参数函数中除了显示指定的参数外的参数,如果是浮点数也是使用整数寄存器传递。

  1. 小于指针字pointer-word的参数使用低位传递,子指针字sub-pointer-word的参数通过栈传递时,使用指针字pointer-word的低地址,因为RISC-V是小端的存储系统。
  2. 当原始参数两倍于指针字pointer-word时通过栈传递,使用自然对齐。当它们使用整数寄存器传递时,使用对齐的偶-奇寄存器对,偶寄存器存低位。比如RV32void foo(int, long long)使用a0传递第一个参数,a2-a3传递第二个参数,因为由偶寄存器对齐,且a2存低位,返回值通过a0传递。
  3. 两倍于指针字pointer-word的参数通过引用传递。
  4. 结构体中部分参数未使用整数寄存器传递的使用栈传递,栈指针sp指向第一个未使用整数寄存器传递的参数。
  5. a0,a1,fa0,fa1用于函数返回值。只有结构体成员只有一个或者两个浮点成员,或者primitives时才使用浮点寄存器返回;其他的由a0-a1组成的两倍指针字的two pointer-words大小返回;更大的返回值通过内存传递;调用者负责分配这个内存,并传递指向该内存的指针,隐含的作为第一个参数传递给被调用者。
  6. 标准RISC-V调用中,栈向下生长,并且保持16字节对齐。
  7. 7个临时整数寄存器t0-t6,12个临时浮点寄存器ft0-ft11在调用过程是可变的,如果后面需要使用则必须由调用者负责保存。其中t表示Temporaries
  • 这里有点疑惑,临时寄存器是被调用者使用的,只有被调用者才知道自己要用哪些寄存器,为什么不是被调用者负责保存?
    这样理解,因为这些寄存器是可变的,对于被调用者来说既然是可变的则可以随便使用,也就是可能被被调用者修改,所以对于调用者来说,如果这些寄存器的值不能被破坏则自己需要负责保存。
  1. 12个整数寄存器s0-s11,12个浮点寄存器fs0-fs11在调用过程是必须保持的,所以如果被调用者需要使用则必须由被调用者保存。

实际上上面的89.,ts寄存器的可变volatile和保持preserved是对被调用者来说的,也就是对被调用者申明,告诉被调用者,

t这些寄存器是可变的,那么被调用者可以随便使用,此时调用者则必须考虑被被调用者随便使用而修改,需要调用者保存;

s这些寄存器是保持的,那么被调用者不能随便使用,如果要用就要负责保存。

所以对于a寄存器也可以这样理解,因为a寄存器用于传递参数,所以是被调用者随便使用的,即不保持的,所以需要调用者负责保存,并赋参数值。

Register ABI Name Description Saver
x0 zero 硬件固定为0 /
x1 ra 返回地址 Caller调用者
x2 sp 栈指针 Callee被调用者
x3 gp 全局指针 /
x4 tp 线程指针 /
x5-x7 t0-t2 临时使用 Caller调用者
x8 s0/fp 保存寄存器/帧指针 Callee被调用者
x9 s1 保存寄存器 Callee被调用者
x10-x11 a0-a1 函数参数/返回值 Caller调用者
x12-x17 a2-a7 函数参数 Caller调用者
x18-x27 s2-s11 保存寄存器 Callee被调用者
x28-x31 t3-t6 临时使用 Caller调用者
f0-f7 ft0-ft7 FP临时使用 Caller调用者
f8-f9 fs0-fs1 FP保存寄存器 Callee被调用者
f10-f11 fa0-fa1 FP函数参数/返回值 Caller调用者
f12-f17 fa2-fa7 FP参数 Caller调用者
f18-f27 fs2-fs11 FP保存寄存器 Callee被调用者
f28-f31 ft8-ft11 FP临时使用 Caller调用者

三.Soft-Float调用约定

在没有浮点硬件,或者不使用F,D,Q扩展的硬件浮点,不使用浮点寄存器,完全由软件实现浮点。

整数参数的传入和返回值和RVG一样。

浮点参数和返回值,通过整数寄存器传递,原则是使用大小相同的整数寄存器传递。

比如RV32

double foo(int, double, long double)

则第一个参数通过a0传递;

第二个参数通过a2a3传递;

第三个参数通过a4传引用传递;

结果通过a0a1传递。

如果是RV64

则第一个参数通过a0传递;

第二个参数通过a1传递;

第三个参数通过a2-a3传递;

结果通过a0传递。

动态舍入模式和产生的异常标志通过C99fenv.h提供的接口访问。

四.总结

从以下几个部分去理解

  1. 寄存器

理解函数参数的传递与返回值,a0-a1,a2-a7,fa0-fa1,fa2-fa7,0-1用于返回值。

理解ra寄存器,函数的返回地址

理解SP栈指针,理解栈的向下生长,理解进入子函数时减少sp分配空间,分配的空间用于存储s寄存器和局部变量使用,和退出子函数时增加sp恢复sp。也就是调用完子函数返回后sp要保持不变。

理解t0-t6,ft0-ft11;s0-s11.fs0-fs11,这里重点站在被调用者角度去理解可变和保持,进而理解谁负责保存寄存器。

  1. 函数调用

jal ra label或者jal ra rd imm简化为伪指令jal label或者jalr rd(立即数为0)。jal跳转即将PC + 4存储到ra寄存器,即函数返回后的下一条执行的指令。jalr类似只是设置PCrd + imm

注意与无条件跳转jal x0 labeljalr x0 rd imm,伪指令j label ,jr rd(立即数为0)的区别,无条件跳转是不返回了的所以不保存返回地址到ra,而是保存到了x0寄存器,而x0寄存器是硬件固定为0的,所以相当于不保存,

两者指令是统一的,这也体现了RISC-V指令设计的简洁统一的美学。

其中jall可以理解为link,类似于ARMLR寄存器的L

  1. 进入和退出函数

除非使用栈传递参数,否则子函数返回后sp必须保持不变。

所有的s寄存器在子函数返回后必须保持,这也是其保持的含义,也是为什么被调用者需要负责保存。

子函数退出时返回ra处执行

函数进入时的处理:减少sp,s寄存器个数和局部变量大小的空间,存储使用到的s寄存器到栈中。如果还有子函数调用则存储ra到栈中(因为子函数的子函数的返回值要存到ra会覆盖ra)。

函数退出时的处理:恢复栈中保存的s寄存器,更新sp值。如果有需要恢复ra值,恢复sp值到函数进入之前的值,返回到ra处执行。

最好通过编写c代码,使用编译工具生成汇编代码,对照c和汇编代码的方式去理解。

五.参考

  1. riscv-calling.pdf [Volume I: RISC-V User-Level ISA V2.1draft:Chapter 18Calling Convention]

  2. Understanding RISC-V Calling Convention.pdf [Nick Riasanovsky]

    审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分