"低レイヤを知りたい人のためのCコンパイラ作成入門"をApple Silicon環境でやってみる
きっかけ
Quoraでプログラマとして10年先も食っていくためにはインタプリタくらい作れないとダメだ.的書き込みを見つけた。
仕事ではライブラリ・フレームワークにおんぶに抱っこで内部で動いてる処理を意識しなくてもできちゃうし、これくらいの仕事は某ChatGPTに取られるんだろうなぁ、みたいなことを想像した。
CSの深い部分の勉強をできる課題を探していたところ、ステップバイステップで自作Cコンパイラを作成する方法を解説する神サイトを見つけた。
神サイト: https://www.sigbus.info/compilerbook
冬休みの自由研究?としてコンパイラ自作をやってみることにした。
神サイトではx86-64のlinux環境を前提として話が進んでいる。
対して当方の環境はApple Silicon(arm64?)のMacOS環境。
linuxはDockerがあるからいいとして、arm64アーキテクチャのアセンブリに読み替えていけばいいのかな?
早速つまづいた。
以下のアセンブリファイルを作成して
.intel_syntax noprefix
.globl main
main:
mov rax, 42
ret
コンパイルを実行
$ docker run --rm -v $HOME/9cc:/9cc -w /9cc compilerbook cc -o test2 test2.s
test2.s: Assembler messages:
test2.s:1: Error: unknown pseudo-op: `.intel_syntax'
test2.s:4: Error: operand 1 must be an integer register -- `mov rax,42'
unknown pseudo-op: `.intel_syntax' はarm64環境だからか。
消しても問題なさげなので消しちゃう。
operand 1 must be an integer registerはarm64環境だとraxって名前のレジスタが無いからか?
https://www.mztn.org/dragon/arm6403reg.html を見たらxとかwとかってレジスタがあるらしいので適当にx0とかに書き換える。
出来上がったのがこれ。
.globl main
main:
mov x0, 42
ret
再度コンパイルして動作確認してみる。
$ docker run --rm -v $HOME/9cc:/9cc -w /9cc compilerbook cc -o test2 test2.s
$ docker run --rm -v $HOME/9cc:/9cc -w /9cc compilerbook ./test2
$ docker run --rm -v $HOME/9cc:/9cc -w /9cc compilerbook echo $?
42
うまくいってるっぽい。
続いてこんなアセンブリを作った。
加算する関数を呼び出すプログラム。
.globl plus, main
plus:
add w0, w1
mov w3, w0
ret
main:
mov w0, 3
mov w1, 4
call plus
ret
コンパイル
$ docker run --rm -v $HOME/9cc:/9cc -w /9cc compilerbook cc -o test3 test3.s
test3.s: Assembler messages:
test3.s:4: Error: comma expected between operands at operand 3 -- `add w0,w1'
test3.s:11: Error: unknown mnemonic `call' -- `call plus'
ぐにゃあ
unknown mnemonic call' --
call plus'はarm64ではcall命令が無いっぽい。
arm64版だとblあたりがそれっぽい?置き換えてみる。
comma expected between operands at operand 3 -- `add w0,w1'はただのシンタックスエラーかな?
どうやらadd x0, x1, x2 (x0 = x1 + x2)とオペランドを3つ指定してあげる必要があるみたい。
参考: https://www.mztn.org/dragon/arm6406calc.html#add
今回はadd w0, w0, w1と書いてみる。
結局できたのが以下
.globl plus, main
plus:
add w0, w0, w1
mov w3, w0
ret
main:
mov w0, 3
mov w1, 4
bl plus
ret
実行したら反応が返ってこなくなった。。。
さっきのbl命令をbに書き換えたら正常に動くようになった。
bl命令は次の命令(今回だとret)の部分に直接戻ってきてしまうからダメだったっぽい。
$ docker run --rm -v $HOME/9cc:/9cc -w /9cc compilerbook cc -o test3 test3
.s
$ docker run --rm -v $HOME/9cc:/9cc -w /9cc compilerbook ./test3
$ docker run --rm -v $HOME/9cc:/9cc -w /9cc compilerbook echo $?
7