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_tsigned intになってしまっているが、x86-64において64bitレジスタの下32bitに書き込むと上位32bitはゼロクリアされてくれるため、レジスタで渡している限りではuint64_tへのキャストが勝手に発生してくれる。

真面目なconst

現状constというキーワードを読み飛ばしているだけ。

最適化

現状、x64をスタックマシンとして使っていて、そこにコンパイルする形になっている。

ということで最適化をしていくことになっているので、やらないとなぁ。