Open6

"低レイヤを知りたい人のためのCコンパイラ作成入門"をApple Silicon環境でやってみる

TokTok

きっかけ

Quoraでプログラマとして10年先も食っていくためにはインタプリタくらい作れないとダメだ.的書き込みを見つけた。
仕事ではライブラリ・フレームワークにおんぶに抱っこで内部で動いてる処理を意識しなくてもできちゃうし、これくらいの仕事は某ChatGPTに取られるんだろうなぁ、みたいなことを想像した。
CSの深い部分の勉強をできる課題を探していたところ、ステップバイステップで自作Cコンパイラを作成する方法を解説する神サイトを見つけた。

神サイト: https://www.sigbus.info/compilerbook

冬休みの自由研究?としてコンパイラ自作をやってみることにした。

TokTok

神サイトではx86-64のlinux環境を前提として話が進んでいる。
対して当方の環境はApple Silicon(arm64?)のMacOS環境。
linuxはDockerがあるからいいとして、arm64アーキテクチャのアセンブリに読み替えていけばいいのかな?

TokTok

早速つまづいた。

以下のアセンブリファイルを作成して

test2.asm
.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とかに書き換える。

出来上がったのがこれ。

test2.asm
.globl main
main:
  mov x0, 42
  ret
TokTok

再度コンパイルして動作確認してみる。

$ 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

うまくいってるっぽい。

TokTok

続いてこんなアセンブリを作った。
加算する関数を呼び出すプログラム。

test3.s
.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と書いてみる。

結局できたのが以下

test3.s
.globl plus, main

plus:
    add w0, w0, w1
    mov w3, w0
    ret

main:
    mov w0, 3
    mov w1, 4
    bl plus
    ret

実行したら反応が返ってこなくなった。。。

TokTok

さっきの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