hsjoihs_c_compilerの現状
この記事はセキュリティキャンプ 修了生進捗 #seccamp OB/OG Advent Calendar 2018の15日目の記事です。
概要
セキュリティ・キャンプ2018で作ってきていた自作Cコンパイラが9月4日にセルフホストを達成した後、どうなっているのかを軽く述べる。
セルフホスト達成時からあった機能
C89の演算子のうちキャスト・ sizeof 値
以外全部
キャストはvoid *
などを用いることによって代用でき、sizeof 値
はsizeof(型)
で代用できるため。あとポインタからポインタを引く場合、sizeof (*ポインタ)
が1, 2, 4, 8以外だとダメ。
goto以外の制御構文全て
正直gotoぐらいすぐ足せると思うし足したい
型: void・char・int・ポインタ・配列・構造体・enumをサポート
shortとかlong longとかunsignedとかがない。charはunsigned charだけど。
文字列リテラル(連結・エスケープシーケンスなども)
流石にこれがないとね
関数から構造体を値として返す
ただし手抜き実装なので、「小さい構造体でアラインメントが4未満」だと動かない。
その後足した機能
文字リテラル
セルフホスト時はギリギリなかった。
構造体を値としてもっと使えるように
(構造体, スカラー)
だったり(構造体 = 構造体).a
だったりフラグ ? 構造体 : 構造体
だったり。
Ubuntu対応
いつのまにかUbuntuで動かなくなっていた。gccだと-no-pieというオプションが必要になったりする、とかの対応をし、再び両方で動くように。
プリプロセッサ
とりあえず#include
(相対パスが正しく動かない)・#define
(ただし置き換え後は単一のトークンであることが必要)・#
・#ifdef
・#ifndef
・#endif
を追加したことにより、2018年10月7日にプリプロセッサ込でセルフホスト。
関数ポインタ
これで(**********printf)("Hello, World!\n");
ができる
構造体のメンバの配列の要素にアクセスすると落ちるバグの修正
「配列へのポインタ」、やはりおそろしい
ポインタからポインタを引いた時、任意のサイズで割れるように。
そもそもコード書く量を減らすための手抜きだったので。
前述の構造体アラインメント問題を修正
そもそもコード書く量を減らすための手抜きだったので。
行コメント
なんか足し忘れてた。
__func__
意外と便利。
可変長引数
作る方も呼ぶ方も対応。
中間表現のdump
--ir=
でダンプを吐けるようにした。今後IRが複数発生したら名前どうしよう。現状では、「英語の語頭文字の確率分布に従って乱数で名前を決め、あとでバクロニムする」を考えている。
現状ない機能
とはいえ、いろいろ足りない機能もまだまだある。
typedef
typedefがない。va_list
とかFILE
とかで困る。
7個以上の引数を取る関数
引数をスタックに積み残す必要があるが、その位置が正しくない。
構造体を値で関数に渡す
スタックだったりレジスタだったりする。面倒。
union
structのオフセットを全て0にすればだいたい実現できるが、自分で使ったこともないしまだ実装していない
enumの初期化子
定数式周りをきちんとやっていない
int array[] = {0, 1, 2, 3};
つらそう
複数のトークンに展開される#define
再帰を禁止したり確保するメモリが増えたりとかがめんどい。Rust使いたい。
空文
これこそ一瞬で足せるのでは。
short, long long, unsigned
暗黙の型変換とかを考えるのがとても険しい。ちなみにmalloc
とかのsize_t
はsigned int
になってしまっているが、x86-64において64bitレジスタの下32bitに書き込むと上位32bitはゼロクリアされてくれるため、レジスタで渡している限りではuint64_t
へのキャストが勝手に発生してくれる。
真面目なconst
現状const
というキーワードを読み飛ばしているだけ。
最適化
現状、x64をスタックマシンとして使っていて、そこにコンパイルする形になっている。
#アンケート
— hsjoihs (@hsjoihs) 2018年12月1日
今後の #hsjoihs_c_compiler:
ということで最適化をしていくことになっているので、やらないとなぁ。