chibiccを読む~Cコンパイラコードリーディング~ ステップ1
トップページ
jupiteroak.hatenablog.com
「低レイヤを知りたい人のためのCコンパイラ作成入門」のCコンパイラを読んでいきます。
www.sigbus.info
ステップ1に該当
github.com
コンパイラのソースコード
main.c
https://github.com/rui314/chibicc/commit/f722daaaae0606115df4ace5a852da23c1a5b0f3#diff-a0cb465674c1b01a07d361f25a0ef2b0214b7dfe9412b7777f89add956da10ecR1
https://github.com/rui314/chibicc/blob/f722daaaae0606115df4ace5a852da23c1a5b0f3/main.c#L1
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "引数の個数が正しくありません\n"); return 1; } printf(".intel_syntax noprefix\n"); printf(".globl main\n"); printf("main:\n"); printf(" mov rax, %d\n", atoi(argv[1])); printf(" ret\n"); return 0; }
コマンドライン引数の個数をチェックする
argcとargvについて
argcはコマンドライン引数の個数を表す値です。argvはコマンドライン引数配列(コマンドライン引数を格納するための配列)で、argv[0]には実行されたプログラム名の文字列、argv[1]以降にはプログラムを実行するときに入力されたコマンドライン引数の文字列が格納されています。
例えば、コマンドラインに「 ./chibicc 123」と入力してプログラムchibiccを実行すると、 argcの値は2となり、argv[0]には"./chibicc"、argv[1]には"123"が格納されます。
fprintf関数について
fprintf関数は、第一引数のファイルポインタが指定するファイルに、第二引数のchar型へのポインタが指定する文字列データを書き込みます。
今回の場合は、標準エラー出力ファイルに、文字列データ"引数の個数が正しくありません\n"が書き込まれるので、このfprintf関数が実行されるとコンソール画面に「引数の個数が正しくありません」と表示されます。
アセンブリコードを生成する
.intel_syntax noprefix について
gas(GNU アセンブラ)はAT&T記法のx86アセンブリ言語をアセンブルするアセンブラですが、.intel_syntaxディレクティブを使用することでIntel記法のx86アセンブリ言語をアセンブルできるようになります。さらに、noprefixを指定することでAT&T記法に特有のプレフェックス(%や$など)を記入する必要がなくなります。
https://www.gnu.org/software/binutils/ → documentation for binutils 2.39 → Assembler (gas) → 9.16.3.1 AT&T Syntax versus Intel Syntax
.globl について
globlディレクティブによって、mainラベルが外部のファイルからでも参照できるようになります。
main:
mov命令が配置されているアドレスにmainラベル(アドレスの別名)を付けています。
mov rax, argv[1]の値
mov命令は、第二オペランドから第一オペランドへデータをコピーします。
ここでは、raxレジスタへatoi関数によって変換されたコマンドライン引数の数値をコピーしています。
ret
ret命令は、サブルーチンの呼び出し元へ制御を戻す命令です。
ここでは、main関数の呼び出し元へ制御を移しています(main関数の処理を終了しています)。
テストコード
test.sh
https://github.com/rui314/chibicc/commit/f722daaaae0606115df4ace5a852da23c1a5b0f3#diff-3722d9ba8feb2d3feac8ce71a209a638d4b404e1c53f937188761181594023e2R1
https://github.com/rui314/chibicc/blob/f722daaaae0606115df4ace5a852da23c1a5b0f3/test.sh#L1
#!/bin/bash assert() { expected="$1" input="$2" ./chibicc "$input" > tmp.s gcc -static -o tmp tmp.s ./tmp actual="$?" if [ "$actual" = "$expected" ]; then echo "$input => $actual" else echo "$input => $expected expected, but got $actual" exit 1 fi } assert 0 0 assert 42 42 echo OK
Makefile
https://github.com/rui314/chibicc/commit/f722daaaae0606115df4ace5a852da23c1a5b0f3#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52R1
https://github.com/rui314/chibicc/blob/f722daaaae0606115df4ace5a852da23c1a5b0f3/Makefile#L1
CFLAGS=-std=c11 -g -static chibicc: main.o $(CC) -o $@ $? $(LDFLAGS) test: chibicc ./test.sh clean: rm -f chibicc *.o *~ tmp* .PHONY: test clean