M1 Macでchibiccを動かす

問題

低レイヤを知りたい人のためのCコンパイラ作成入門のリファレンス実装であるchibiccをM1 Macbook Air のdockerで動かしたところ、make testを実行した際に次のエラーが出た。

sbite@macbookair chibicc %  docker run --rm -v $PWD:/tmp -w /tmp compilerbook make test
./chibicc -Iinclude -Itest -c -o test/line.o test/line.c
/tmp/chibicc-eSJ6iQ: Assembler messages:
/tmp/chibicc-eSJ6iQ:240: Error: unknown mnemonic `push' -- `push %rbp'
/tmp/chibicc-eSJ6iQ:241: Error: operand 1 must be an integer register -- `mov %rsp,%rbp'
/tmp/chibicc-eSJ6iQ:242: Error: operand 1 must be an integer or stack pointer register -- `sub $144,%rsp'
/tmp/chibicc-eSJ6iQ:243: Error: operand 1 must be an integer register -- `mov %rsp,-8(%rbp)'
/tmp/chibicc-eSJ6iQ:244: Error: unknown mnemonic `movl' -- `movl $0,-144(%rbp)'
/tmp/chibicc-eSJ6iQ:245: Error: unknown mnemonic `movl' -- `movl $48,-140(%rbp)'
/tmp/chibicc-eSJ6iQ:246: Error: unknown mnemonic `movq' -- `movq %rbp,-136(%rbp)'
…

原因

付録3:Dockerを使った開発環境の作成を参考にしてLinuxのdockerイメージを作成したが、この方法だとM1 Macではaarch64版のLinuxがダウンロードされるっぽい(Apple M1はarm系のチップなので、それはそう)

sbite@macbookair chibicc %  docker run --rm -v $PWD:/tmp -w /tmp compilerbook uname -a
Linux b551daa93102 5.10.25-linuxkit #1 SMP PREEMPT Tue Mar 23 09:24:45 UTC 2021 aarch64 aarch64 aarch64 GNU/Linux

chibiccはx86_64のアセンブリを出力するので、aarch64のアセンブラでは解釈できないものになっていて、これが原因でエラーが出ていそう。

解決策

M1 MacにはRossetaというx86_64をエミュレーションする機能がついていて、これを利用することで、x86_64版のLinuxをdocker経由で動かすことができた。
まずはmacRossetaを入れる(Rossetaの入れ方はメモってなかったのでググってください…)
インストールが終わると、arch -x86_64 uname -mを実行してx86_64が出力されるようになるはず。

sbite@macbookair chibicc % arch -x86_64 uname -m
x86_64

その後、オプションに--platform linux/amd64 を付けてdockerイメージを作成する

sbite@macbookair chibicc % docker build -t compilerbook_x86_64 https://www.sigbus.info/compilerbook/Dockerfile  --platform linux/amd64
[+] Building 1.4s (9/9) FINISHED                                                
 => CACHED [internal] load remote build context                            0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest           1.3s
 => [1/6] FROM docker.io/library/ubuntu:latest@sha256:3c9c713e0979e9bd606  0.0s
 => CACHED [2/6] RUN apt update                                            0.0s
 => CACHED [3/6] RUN DEBIAN_FRONTEND=noninteractive apt install -y gcc ma  0.0s
 => CACHED [4/6] RUN adduser --disabled-password --gecos '' user           0.0s
 => CACHED [5/6] RUN echo 'user ALL=(root) NOPASSWD:ALL' > /etc/sudoers.d  0.0s
 => CACHED [6/6] WORKDIR /home/user                                        0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:7b022fe760762b094441e9f6d01c415d3aa52b6ed4105  0.0s
 => => naming to docker.io/library/compilerbook_x86_64                     0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

make clean今までに作成した.oファイル等を削除しておく(これを忘れて無限にハマった…)

sbite@macbookair chibicc %  docker run --rm -v $PWD:/tmp -w /tmp compilerbook_x86_64 make clean
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
rm -rf chibicc tmp* test/line.exe test/constexpr.exe test/decl.exe test/variable.exe test/const.exe test/struct.exe test/arith.exe test/offsetof.exe test/varargs.exe test/typedef.exe test/asm.exe test/vla.exe test/builtin.exe test/cast.exe test/complit.exe test/pointer.exe test/enum.exe test/bitfield.exe test/macro.exe test/float.exe test/extern.exe test/function.exe test/union.exe test/compat.exe test/string.exe test/atomic.exe test/attribute.exe test/pragma-once.exe test/literal.exe test/usualconv.exe test/tls.exe test/alignof.exe test/alloca.exe test/sizeof.exe test/commonsym.exe test/unicode.exe test/stdhdr.exe test/initializer.exe test/control.exe test/generic.exe test/typeof.exe test/*.s test/*.exe stage2
find * -type f '(' -name '*~' -o -name '*.o' ')' -exec rm {} ';'

その後make testなどとすると、ちゃんと動くことが確認できる。

sbite@macbookair chibicc %  docker run --rm -v $PWD:/tmp -w /tmp compilerbook_x86_64 make test
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
cc -std=c11 -g -fno-common -Wall -Wno-switch   -c -o tokenize.o tokenize.c
cc -std=c11 -g -fno-common -Wall -Wno-switch   -c -o unicode.o unicode.c
cc -std=c11 -g -fno-common -Wall -Wno-switch   -c -o hashmap.o hashmap.c
cc -std=c11 -g -fno-common -Wall -Wno-switch   -c -o type.o type.c
(snip)
testing -MD ... passed
testing -fPIC ... passed
testing #include_next ... passed
testing -static ... passed
testing -static ... passed
testing -shared ... passed
testing -L ... passed
testing -Wl, ... passed
testing -Xlinker ... passed
OK

参考にした記事

zenn.dev