diff --git a/book/.vitepress/config.mts b/book/.vitepress/config.mts index 2a37307..1af8071 100644 --- a/book/.vitepress/config.mts +++ b/book/.vitepress/config.mts @@ -55,6 +55,10 @@ export default defineConfig({ text: "符號檢查", link: "/零.一版/符號檢查", }, + { + text: "精五真言生成", + link: "/零.一版/精五真言生成", + }, ], }, ], diff --git "a/book/\351\233\266\357\274\216\344\270\200\347\211\210/\347\262\276\344\272\224\347\234\237\350\250\200\347\224\237\346\210\220.md" "b/book/\351\233\266\357\274\216\344\270\200\347\211\210/\347\262\276\344\272\224\347\234\237\350\250\200\347\224\237\346\210\220.md" new file mode 100644 index 0000000..b37d6c9 --- /dev/null +++ "b/book/\351\233\266\357\274\216\344\270\200\347\211\210/\347\262\276\344\272\224\347\234\237\350\250\200\347\224\237\346\210\220.md" @@ -0,0 +1,67 @@ +至此,貧道已經展示了零.一版音界咒的分詞、剖析、語義檢查,若程式能通過這些步驟,代表它完全合法。接下來,就可以生成目標碼了,在本指引中,貧道會示範如何生成精五真言(RISC-V)。 + +## 變數儲存 +熟悉 C 語言的道友想必都曉得,全域變數與區域變數在程序執行時是放在不同位置。全域變數會放在數據段(data section),在整個程序執行的過程都佔用一塊記憶體空間;而區域變數則是則是存放在函式調用時臨時開的棧禎。 + +零.一版音界咒的變數可以視做全域的,畢竟該版本尚無函式調用的概念。 + +### 精五真言的數據段 + +很容易就能用精五真言設定全域變數,一下是範例`數據段.S`: + +```assembly +.section .data +甲: + .word 50 # .word 表示開闢 32 位元的空間,該空間的值為 50 + +.section .text +.global _start + +_start: + lw t0, 甲 # t0 = *(u32*)甲 + + li a7, 93 # RISCV Linux 中 exit 系統呼叫編號是 93 + mv a0, t0 # a0 = t0 + ecall # 執行系統呼叫 exit(t0) +``` + +同樣交叉編譯並以 qemu 模擬 +``` +riscv64-unknown-elf-gcc -nostdlib 數據段.S # 編譯後應得 a.out 檔案 +qemu-riscv64 a.out # qemu-riscv64 並非單單模擬裸機,還實作了部分系統呼叫 +echo $? # 可以看到上一個程序的結束碼是 50 +``` + +`數據段.S` 首先在數據段 `.section .data` ,中用 `.word` 開闢 32 位元的空間,前方的`甲`是一個標籤,在後續程式段的真言中會被代換為該空間的位址。 + +再來看 `_start` 的第一行 `lw t0, 甲`,lw 是 load word 的縮寫,效果是從位址甲開始讀取 32 位元放進 t0 暫存器。 `lw` 執行完後, `t0` 就是 `50` 了,最後 `mv a0, t0` 把程序結束碼設為 50。 + +與 `lw` 相對應,`sw`(store word)能夠將暫存器的值寫入某個記憶體位址,但 `sw` 要多加一個參數,`sw t0, 甲, rt`, `rt` 可以是任意通用暫存器。 + + +### 選讀:為什麼 sw 要三個參數 +接三個參數的 `sw rd, 標籤, rt` 是偽指令,組譯後會變為兩條指令: + +``` +auipc rt, 標籤[31:12] +sw rd, 標籤[31:12](rt) +``` + +其大概意思是用先把 rt 的值弄成成標籤的位址,再把 rt 所在位址的 32 位元存進 rd 。 + +那為何 `lw rd, 標籤` 就不需要額外暫存器來幫忙存位址呢?它也是會編譯成兩條真言的偽指令吧! 因為`rd`在載入時能重複用。 +``` +auipc rd, 標籤[31:12] # 反正等等 rd 的值等等也要被改了,順便當位址用 +lw rd, 標籤[31:12](rd) # rd 既是記憶體位址,又是要被寫入的暫存器 +``` + +`sw` 的 rd 要是重複用,還沒把它的值寫到記憶體,自己就先被汙染了: + +``` +auipc rd, 標籤[31:12] # rd 的值已被汙染 +sw rd, 標籤[31:12](rd) # 把被汙染的值寫到記憶體 +``` + +所以 `sw rd, 標籤, rt` 的第三個參數 rt 省不了。 + +## 運算 diff --git "a/book/\351\233\266\357\274\216\344\270\200\347\211\210/\347\267\250\350\255\257\347\233\256\346\250\231\357\274\232\347\262\276\344\272\224\351\226\200\357\274\210RISC-V\357\274\211\347\234\237\350\250\200\346\245\265\347\260\241\345\255\220\351\233\206.md" "b/book/\351\233\266\357\274\216\344\270\200\347\211\210/\347\267\250\350\255\257\347\233\256\346\250\231\357\274\232\347\262\276\344\272\224\351\226\200\357\274\210RISC-V\357\274\211\347\234\237\350\250\200\346\245\265\347\260\241\345\255\220\351\233\206.md" index 31cb9d3..aff7a21 100644 --- "a/book/\351\233\266\357\274\216\344\270\200\347\211\210/\347\267\250\350\255\257\347\233\256\346\250\231\357\274\232\347\262\276\344\272\224\351\226\200\357\274\210RISC-V\357\274\211\347\234\237\350\250\200\346\245\265\347\260\241\345\255\220\351\233\206.md" +++ "b/book/\351\233\266\357\274\216\344\270\200\347\211\210/\347\267\250\350\255\257\347\233\256\346\250\231\357\274\232\347\262\276\344\272\224\351\226\200\357\274\210RISC-V\357\274\211\347\234\237\350\250\200\346\245\265\347\260\241\345\255\220\351\233\206.md" @@ -9,7 +9,7 @@ ## 實驗環境架設 -絕大部分的人手邊都沒有精五架構的板子,需要先安裝 +絕大部分的人手邊都沒有精五架構的板子,在其他架構的機器上,需要先安裝一些工具才能模擬精五架構: - 交叉編譯器工具鏈 - 精五模擬器(本作選擇使用 qemu)