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経由で動かすことができた。
まずはmacにRossetaを入れる(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