risc-v C程式呼叫規範 (calling conventions)

2020-08-14 21:08:16

risc-v C程式呼叫規範 (calling conventions)

在上一篇文章裡,已經介紹瞭如何搭建xv6的執行環境,在這一篇文章介紹一下risc-v C呼叫規範。

  1. 首先看一下C語言下的數據型別在risc-v下所佔據的大小,如下圖:
    在这里插入图片描述
    可以看出除了long和void*的大小是和平臺有關,其他型別無論是在32位元還是64位元平臺上,他們的大小都是一樣的。

  2. 函數呼叫規範

在risc-v平臺上,有8個整形暫存器(a0a7),8個浮點暫存器(fa0fa7)。

a.如果函數的參數是結構體成員,那麼每個參數要按照所在平臺上指針型別大小對齊,比如32位元平臺4位元組對齊,64位元平臺8位元組對齊。由於至多有8個暫存器,所以結構體至多8個成員會被放在暫存器中,剩餘的部分被存放在棧上,sp指向第一個沒有被存放在暫存器上的結構體成員。如果第i個參數是整形型別,那麼就存放在整形暫存器ai上,如果第i個參數是浮點數型別,那麼就存放在浮點暫存器fai上。聯合體中的浮點成員或者結構體中的陣列成員也是通過整形暫存器來傳遞的。變長參數函數的浮點參數傳遞也是通過整形暫存器來傳遞(明確宣告浮點暫存器傳遞的除外),最典型的變長參數函數比如printf。

b. 小於1個指針字長的參數被存在暫存器的低位,比如char型別的參數被存在整形暫存器的低8位元。同理小於1個指針字長的參數存在棧上也是存放在記憶體的低地址上,這和risc-v的記憶體系統是小端系統是一致的。如果參數是基本型別並且是指針字長的兩倍,那麼偶數暫存器存放的是低位元組,比如void foo(int a,long long b)那麼暫存器a0存放a,暫存器a2和a3存放b,a2存放參數b的低位,跳過了a1。如果參數是基本型別大於指針字長的兩倍,那麼這些參數的傳遞是通過參照。

c. 函數返回值如果是基本型別或者只包含一兩個成員的基本結構體的成員,存放在相應的整形暫存器a0和a1,浮點暫存器fa0和fa1. 大於兩個指針字長的返回值存放在記憶體上(該記憶體有呼叫者分配,並且把指針作爲第一個參數傳遞給被調者)。

d. 棧是從高地址向低地址方向的, 並且是16位元組對齊的。

e. 暫存器t0t6,ft0ft11被稱爲臨時暫存器,由呼叫者儲存。s0~s11, fs0~fs11由被調者儲存。