Skip to content

Commit d741589

Browse files
committed
真言生成.變數儲存
1 parent 8858b6c commit d741589

3 files changed

Lines changed: 72 additions & 1 deletion

File tree

book/.vitepress/config.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ export default defineConfig({
5555
text: "符號檢查",
5656
link: "/零.一版/符號檢查",
5757
},
58+
{
59+
text: "精五真言生成",
60+
link: "/零.一版/精五真言生成",
61+
},
5862
],
5963
},
6064
],
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
至此,貧道已經展示了零.一版音界咒的分詞、剖析、語義檢查,若程式能通過這些步驟,代表它完全合法。接下來,就可以生成目標碼了,在本指引中,貧道會示範如何生成精五真言(RISC-V)。
2+
3+
## 變數儲存
4+
熟悉 C 語言的道友想必都曉得,全域變數與區域變數在程序執行時是放在不同位置。全域變數會放在數據段(data section),在整個程序執行的過程都佔用一塊記憶體空間;而區域變數則是則是存放在函式調用時臨時開的棧禎。
5+
6+
零.一版音界咒的變數可以視做全域的,畢竟該版本尚無函式調用的概念。
7+
8+
### 精五真言的數據段
9+
10+
很容易就能用精五真言設定全域變數,一下是範例`數據段.S`
11+
12+
```assembly
13+
.section .data
14+
甲:
15+
.word 50 # .word 表示開闢 32 位元的空間,該空間的值為 50
16+
17+
.section .text
18+
.global _start
19+
20+
_start:
21+
lw t0, 甲 # t0 = *(u32*)甲
22+
23+
li a7, 93 # RISCV Linux 中 exit 系統呼叫編號是 93
24+
mv a0, t0 # a0 = t0
25+
ecall # 執行系統呼叫 exit(t0)
26+
```
27+
28+
同樣交叉編譯並以 qemu 模擬
29+
```
30+
riscv64-unknown-elf-gcc -nostdlib 數據段.S # 編譯後應得 a.out 檔案
31+
qemu-riscv64 a.out # qemu-riscv64 並非單單模擬裸機,還實作了部分系統呼叫
32+
echo $? # 可以看到上一個程序的結束碼是 50
33+
```
34+
35+
`數據段.S` 首先在數據段 `.section .data` ,中用 `.word` 開闢 32 位元的空間,前方的``是一個標籤,在後續程式段的真言中會被代換為該空間的位址。
36+
37+
再來看 `_start` 的第一行 `lw t0, 甲`,lw 是 load word 的縮寫,效果是從位址甲開始讀取 32 位元放進 t0 暫存器。 `lw` 執行完後, `t0` 就是 `50` 了,最後 `mv a0, t0` 把程序結束碼設為 50。
38+
39+
`lw` 相對應,`sw`(store word)能夠將暫存器的值寫入某個記憶體位址,但 `sw` 要多加一個參數,`sw t0, 甲, rt``rt` 可以是任意通用暫存器。
40+
41+
42+
### 選讀:為什麼 sw 要三個參數
43+
接三個參數的 `sw rd, 標籤, rt` 是偽指令,組譯後會變為兩條指令:
44+
45+
```
46+
auipc rt, 標籤[31:12]
47+
sw rd, 標籤[31:12](rt)
48+
```
49+
50+
其大概意思是用先把 rt 的值弄成成標籤的位址,再把 rt 所在位址的 32 位元存進 rd 。
51+
52+
那為何 `lw rd, 標籤` 就不需要額外暫存器來幫忙存位址呢?它也是會編譯成兩條真言的偽指令吧! 因為`rd`在載入時能重複用。
53+
```
54+
auipc rd, 標籤[31:12] # 反正等等 rd 的值等等也要被改了,順便當位址用
55+
lw rd, 標籤[31:12](rd) # rd 既是記憶體位址,又是要被寫入的暫存器
56+
```
57+
58+
`sw` 的 rd 要是重複用,還沒把它的值寫到記憶體,自己就先被汙染了:
59+
60+
```
61+
auipc rd, 標籤[31:12] # rd 的值已被汙染
62+
sw rd, 標籤[31:12](rd) # 把被汙染的值寫到記憶體
63+
```
64+
65+
所以 `sw rd, 標籤, rt` 的第三個參數 rt 省不了。
66+
67+
## 運算

book/零.一版/編譯目標:精五門(RISC-V)真言極簡子集.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
## 實驗環境架設
1111

12-
絕大部分的人手邊都沒有精五架構的板子,需要先安裝
12+
絕大部分的人手邊都沒有精五架構的板子,在其他架構的機器上,需要先安裝一些工具才能模擬精五架構:
1313

1414
- 交叉編譯器工具鏈
1515
- 精五模擬器(本作選擇使用 qemu)

0 commit comments

Comments
 (0)