|
| 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 | +## 運算 |
0 commit comments