- 一.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調用約定
a0-a7
,fa0-fa7
:用于函數傳遞參數,其中0-1
用于返回值,a
表示arguments
。
都是調用者負責保存,因為是傳參肯定是在函數調用前就要準備好,所部不可能是被調用者去負責保存。
- 如果函數參數為結構體的字段,每一個都是指針對齊的,則參數寄存器是結構體前面8個指針字
pointer-words
的影子shadow
。
如果是小于8個的浮點值,則使用fai
傳遞;小于8個的整數則使用ai
傳遞。
如果浮點參數是聯合體unions
的字段,或者結構體的數組字段,則使用整數寄存器傳遞。
另外可變參數函數中除了顯示指定的參數外的參數,如果是浮點數也是使用整數寄存器傳遞。
- 小于指針字
pointer-word
的參數使用低位傳遞,子指針字sub-pointer-word
的參數通過棧傳遞時,使用指針字pointer-word
的低地址,因為RISC-V
是小端的存儲系統。 - 當原始參數兩倍于指針字
pointer-word
時通過棧傳遞,使用自然對齊。當它們使用整數寄存器傳遞時,使用對齊的偶-奇
寄存器對,偶寄存器存低位。比如RV32
的void foo(int, long long)
使用a0
傳遞第一個參數,a2-a3
傳遞第二個參數,因為由偶寄存器對齊,且a2
存低位,返回值通過a0
傳遞。 - 兩倍于指針字
pointer-word
的參數通過引用傳遞。 - 結構體中部分參數未使用整數寄存器傳遞的使用棧傳遞,棧指針
sp
指向第一個未使用整數寄存器傳遞的參數。 a0,a1
,fa0,fa1
用于函數返回值。只有結構體成員只有一個或者兩個浮點成員,或者primitives
時才使用浮點寄存器返回;其他的由a0-a1
組成的兩倍指針字的two pointer-words
大小返回;更大的返回值通過內存傳遞;調用者負責分配這個內存,并傳遞指向該內存的指針,隱含的作為第一個參數傳遞給被調用者。- 標準
RISC-V
調用中,棧向下生長,并且保持16字節對齊。 - 7個臨時整數寄存器
t0-t6
,12個臨時浮點寄存器ft0-ft11
在調用過程是可變的,如果后面需要使用則必須由調用者負責保存。其中t
表示Temporaries
。
- 這里有點疑惑,臨時寄存器是被調用者使用的,只有被調用者才知道自己要用哪些寄存器,為什么不是被調用者負責保存?
這樣理解,因為這些寄存器是可變的,對于被調用者來說既然是可變的則可以隨便使用,也就是可能被被調用者修改,所以對于調用者來說,如果這些寄存器的值不能被破壞則自己需要負責保存。
- 12個整數寄存器
s0-s11
,12個浮點寄存器fs0-fs11
在調用過程是必須保持的,所以如果被調用者需要使用則必須由被調用者保存。
實際上上面的8
和9.
,t
和s
寄存器的可變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
傳遞;
第二個參數通過a2
和a3
傳遞;
第三個參數通過a4
傳引用傳遞;
結果通過a0
和a1
傳遞。
如果是RV64
則
則第一個參數通過a0
傳遞;
第二個參數通過a1
傳遞;
第三個參數通過a2-a3
傳遞;
結果通過a0
傳遞。
動態舍入模式和產生的異常標志通過C99
的fenv.h
提供的接口訪問。
四.總結
從以下幾個部分去理解
- 寄存器
理解函數參數的傳遞與返回值,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
,這里重點站在被調用者角度去理解可變和保持,進而理解誰負責保存寄存器。
- 函數調用
jal ra label
或者jal ra rd imm
簡化為偽指令jal label
或者jalr rd
(立即數為0)。jal
跳轉即將PC + 4
存儲到ra
寄存器,即函數返回后的下一條執行的指令。jalr
類似只是設置PC
為rd + imm
。
注意與無條件跳轉jal x0 label
和jalr x0 rd imm
,偽指令j label
,jr rd
(立即數為0)的區別,無條件跳轉是不返回了的所以不保存返回地址到ra
,而是保存到了x0
寄存器,而x0
寄存器是硬件固定為0的,所以相當于不保存,
兩者指令是統一的,這也體現了RISC-V指令設計的簡潔統一的美學。
其中jal
的l
可以理解為link
,類似于ARM
的LR
寄存器的L
。
- 進入和退出函數
除非使用棧傳遞參數,否則子函數返回后sp
必須保持不變。
所有的s
寄存器在子函數返回后必須保持,這也是其保持的含義,也是為什么被調用者需要負責保存。
子函數退出時返回ra
處執行
函數進入時的處理:減少sp
,s
寄存器個數和局部變量大小的空間,存儲使用到的s
寄存器到棧中。如果還有子函數調用則存儲ra
到棧中(因為子函數的子函數的返回值要存到ra
會覆蓋ra
)。
函數退出時的處理:恢復棧中保存的s
寄存器,更新sp
值。如果有需要恢復ra
值,恢復sp
值到函數進入之前的值,返回到ra
處執行。
最好通過編寫c
代碼,使用編譯工具生成匯編代碼,對照c
和匯編代碼的方式去理解。
五.參考
-
代碼
+關注
關注
30文章
4788瀏覽量
68603 -
編譯器
+關注
關注
1文章
1634瀏覽量
49129 -
數據類型
+關注
關注
0文章
236瀏覽量
13624 -
RISC-V
+關注
關注
45文章
2277瀏覽量
46158
發布評論請先 登錄
相關推薦
評論