音界咒的編譯目標是精五門(RISC-V)真言,精五門真言本就十分精簡,在零.一版,更是僅需要
- 整數加減乘除
- 指定暫存器的值
等寥寥幾個指令而已。
但在介紹這些指令之前,先來寫個最簡單的範例,並讓它動起來。
實驗環境架設
絕大部分的人手邊都沒有精五架構的板子,在其他架構的機器上,需要先安裝一些工具才能模擬精五架構:
- 交叉編譯器工具鏈
- 精五模擬器(本作選擇使用 qemu)
以下是 ubuntu 的安裝指令。
sudo apt install gcc-riscv64-unknown-elf # 安裝編譯目標為 riscv64 的工具鏈
sudo apt install qemu-user # 安裝可執行 linux 執行檔的 qemu
返回 100
以下是貧道所能構造的最簡易的範例,它一啟動就以 100 當結束碼關閉程序:
assembly
.section .text
.global _start
_start:
li a7, 93 # RISCV Linux 中 exit 系統呼叫編號是 93
li a0, 100 # a0 是函數呼叫時,第一個參數位置
ecall # 執行系統呼叫 exit(100)
將之命名為 100.S
。
編譯、執行
riscv64-unknown-elf-gcc -nostdlib 100.S # 編譯後應得 a.out 檔案
qemu-riscv64 a.out # qemu-riscv64 並非單單模擬裸機,還實作了部分系統呼叫
echo $? # 可以看到上一個程序的結束碼是 100
整數加減乘除
assembly
add 目標, 源1, 源2
sub 目標, 源1, 源2
mul 目標, 源1, 源2
div 目標, 源1, 源2
以上就是加減乘除四個指令了,此處的目標、源1、源2,都是暫存器的名字。精五(RISC-V)有 32 個整數通用暫存器,在零.一版的編譯目標中,僅使用臨時暫存器 t0 ~ t6 就可以了。
除了讓暫存器跟暫存器加減乘除,精五也支援讓暫存器與(12位)立即數做加運算。
assembly
addi 目標, 源, 立即數
由於立即數可以寫負數,就不支援減立即數的操作了,畢竟加上一個負數就等同於減。
指定暫存器的值
li 目標, 立即數 # 將目標暫存器的值設為立即數
mv 目標, 源 # 將目標暫存器的值設為源暫存器的值
li
跟 mv
都是偽指令,也就是說,在組譯階段,指令會被變成一到多個真實指令。
例如當立即數可用 12 位元表示時,li 目標, 立即數
會被譯為 addi 目標, x0, 立即數
。其中 x0
是一個特殊的唯獨暫存器,其值永遠為 0。
而 mv 目標, 源
會被譯為 addi 目標, 源, 0
。
音界咒編譯實例
音界
元.甲=(1+3)*4
甲+1
編譯出的精五真言,其結束碼定義為:若最後一行是算式,則為算式求值結果,在上述範例中,即是「甲+1」的值。若最後一行是變數宣告,結束碼定義為該變數的值。
assembly
.section .text
.global _start
_start:
li t0, 1 # t0 = 1
li t1, 3 # t1 = 3
add t0, t0, t1 # t0 = t0 + t1
li t1, 4 # t1 = 4
mul t0, t0, t1 # t0 = t0 * t1
addi t0, t0, 1 # t0 = t0 + 1
li a7, 93 # RISCV Linux 中 exit 系統呼叫編號是 93
mv a0, t0 # a0 = t0
ecall # 執行系統呼叫 exit(t0)
試著編譯執行看看,並驗證結束碼是否是 17。