-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
113 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,16 @@ | ||
|
||
|
||
## 零.二版引入 | ||
|
||
## 術 | ||
### 術 | ||
函式 | ||
|
||
### 外術 | ||
外部函式 | ||
|
||
### 施者 | ||
caller | ||
|
||
### 受者 | ||
callee | ||
|
||
## 符號 | ||
### 基括號 | ||
〖〗 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
在上一章討論了區域變數如何存放在棧中,在[零.一版](../零.一版/精五真言生成.md)中提及了全域變數如何生成。現在,還剩下一種變數沒有討論——**參數**。 | ||
|
||
## 精五真言施術約定 | ||
精五有 32 個通用暫存器,施術時 `call 術` 這個偽指令做的不過是將咒指針(program counter)跳躍到`術`所在位址,把就位址放到 `ra` 暫存器而已。 | ||
|
||
施者(caller)如何傳遞資訊給受者(callee)呢?其實怎樣都可以,無論是丟到棧上的某個位置還是丟到特定暫存器都可以。總之**講好就好**。如果不同編譯器不按照同個約定來傳遞參數,那這些編譯器編譯出來的術就無法互相調用了。 | ||
|
||
精五的[標準施展約定](https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf)規定在整數情況下,使用 `a0` ~ `a7` 暫存器來傳遞變數。這些暫存器吾人稱之為參數暫存器。(a 即是 argument 的縮寫) | ||
|
||
而術結束後,會將其歸值(return value)放在 `a0` 與 `a1`,歸值若僅一個字長,只要看 `a0` 就好了。 | ||
|
||
貧道用 gcc 編譯個簡單的 C 程式(音界咒當前版本也依賴類似外術),來看看是否按照這個約定就能呼叫到它了。 | ||
|
||
## 編譯外術(外部函式) | ||
|
||
將以下 C 代碼存入 `曰.c` 檔案中。 | ||
|
||
```c | ||
#include <stdio.h> | ||
#include <inttypes.h> | ||
|
||
int64_t print_int(int64_t number) { | ||
printf("%" PRId64 "\n", number); | ||
return 111; | ||
} | ||
``` | ||
執行以下指令來編譯該檔案 | ||
```sh | ||
riscv64-unknown-elf-gcc -c 曰.c -o 曰.o | ||
riscv64-unknown-elf-objcopy --redefine-sym print_int=曰 曰.o | ||
``` | ||
|
||
C 語言不支援非 ASCII 的字符,得先編譯出目的檔 `曰.o` 之後,再將其符號從 `print_int` 抽換成 `曰`。 | ||
|
||
## 施術範例 | ||
|
||
再將以下檔案存到 `施展.S`。 | ||
|
||
```assembly | ||
.section .text | ||
.global main | ||
main: | ||
li a0, 17 | ||
call 曰 | ||
call 曰 | ||
li a7, 93 # ecall號碼93表示退出 | ||
li a0, 0 | ||
ecall | ||
``` | ||
|
||
用以下指令組譯 `施展.S` 並鏈結`曰.o` | ||
``` | ||
riscv64-unknown-elf-gcc 施展.S 曰.o | ||
``` | ||
再以 qemu 執行生成的執行檔 `a.out` | ||
|
||
``` | ||
qemu-riscv64 a.out | ||
``` | ||
會看到終端輸出 | ||
``` | ||
17 | ||
111 | ||
``` | ||
第一行 `17` 正是吾人放進 `a0` 的值,而第二行的 `111` 恰好就是曰的歸值,第一個 `call 曰` 結束之後,`a0` 已經被改為 `111` ,立刻再施展一次 `曰` ,果然輸出了 `111`。 | ||
|
||
看來 gcc 確實按照這個約定在傳遞參數與回傳值,音界咒編譯器也遵照約定,以在未能完全自舉之前方便與塵界之術互動。 | ||
|
||
## 儲存參數 | ||
|
||
既然在術開始之前,參數就已被施者填入 `a0` ~ `a7` 之中,那能否每次需要讀取參數時就直接使用暫存器呢?不能,因為術有可能還要去調用其他術,這是又得修改 `a0` ~ `a7` 來傳遞參數了。 | ||
|
||
還是只能老方法全都存到棧裡了。 | ||
|
||
如果不需要再調用其他術,大可以就放在參數暫存器裡,但零.二版音界咒的實作先不做這個優化。 | ||
|
||
來看個範例: | ||
|
||
```音界 | ||
術.甲(子、丑)【 | ||
元.天=1 | ||
元.地=1 | ||
元.玄=1 | ||
元.黃=1 | ||
】 | ||
``` | ||
|
||
執行後,棧應該要是 | ||
|
||
![加入參數的精五棧圖解](../image/參數精五棧圖解.png) |