2 ポイント 投稿者 GN⁺ 2026-02-08 | 1件のコメント | WhatsAppで共有
  • x86-16アセンブリで書かれた SectorC は、x86マシンの ブートセクタ(512バイト) に収まる超小型Cコンパイラで、実際に動作するプログラムを書けるだけの C言語の部分集合 をサポートする
  • グローバル変数、関数、if/while文、演算子、ポインタのデリファレンス、コメント、インラインアセンブリ などを含み、最小限の構成でも完全なプログラム実行が可能
  • トークナイザを単純化するため、空白ベースのトークン化atoi() ハッシュを利用した Barely C言語 を設計し、既存のC文法を保ちながらも極端なサイズ削減を実現
  • コード最適化の過程で ジャンプ削減、呼び出し統合、8ビットオフセット活用、stosw/lodsw 使用 など、さまざまなアセンブリレベルの圧縮技法を適用し、468バイトから303バイトへ縮小
  • 結果として、512バイトの中に トークナイザ、パーサ、コード生成器、ランタイム をすべて含む完全なCコンパイラを実装し、ソフトウェア極小化の極端な実例 を示した

SectorC 概要

  • SectorCは x86-16アセンブリ で書かれたCコンパイラで、512バイトのブートセクタ に完全に収まる
    • GitHubリポジトリ: xorvoid/sectorc
    • 対応言語は実際のプログラム作成が可能なレベルのC部分集合
  • 対応機能には グローバル変数、関数、制御文(if/while)、各種演算子、ポインタのデリファレンス、インラインアセンブリ、コメント などが含まれる
  • 例として VGAモードでサイン波アニメーションを描画するコード が示されている

設計背景とアプローチ

  • 既存のCトークナイザは512バイトでは不可能なほど大きいため、言語構造そのものを単純化 する必要があった
  • Big Insight #1: Forth言語のように 空白で区切られたトークン構造 を導入し、「Barely C」という変形言語を設計
    • 例: int(main)(){while(!done){ のような構文を1つの「メガトークン」として処理
    • 既存のCコンパイラでも依然として有効なCコードとして認識される
  • Big Insight #2: atoi() 関数を ハッシュ関数 のように使ってトークンを数値に変換
    • 整数リテラル、キーワード、識別子をすべて atoi() の結果値として扱う
    • 識別子は64K配列のインデックスとしてアクセスする

Barely C の実装

  • 最初の実装は 468バイト で、atoi ベースのトークンを使う 再帰下降パーサ 構造
    • シンボルテーブルなしで64Kセグメントへハッシュ値で直接アクセス
    • コード生成はOTCCスタイルで ax レジスタを結果の格納先として使う
  • その後 バイトスレッドコード(byte-threaded code) の実験を通じてForth式構造も試したが、512バイト内ではかえって非効率だったため破棄された

コード極小化の技法

  • 直線的な構造に戻して 468バイト → 303バイト に縮小
    • ジャンプ削減(fall-through)tail-call呼び出し統合(call fusion)stosw/lodsw 活用8ビットジャンプオフセット維持 などの技法を使用
  • 207バイトの空き領域を確保し、追加機能を実装

完全なC機能への拡張

  • 200バイト追加して 完全なC文法対応 を達成
    • ネストした if/while ブロック、さまざまな 二項演算子 (+, -, *, &, |, ^, <<, >>, ==, !=, <, >, <=, >=)
    • 関数定義と再帰呼び出しインラインアセンブリ (asm)1行/複数行コメント をサポート
    • 演算子テーブル (binary_oper_tbl) により各演算子を4バイトで定義し、14個の演算子を56バイトで処理

文法構造

  • 全体の文法は programvar_declfunc_declstatementexpr などで構成される
  • // および /* */ コメントの両方をサポート
  • 文法定義テキスト自体は704バイトで、実装そのものより大きい

インラインアセンブリとランタイム

  • asm 構文を通じて x86-16機械語を直接挿入 可能
    • I/O処理のために必須の機能
  • ランタイム(rt/)はCで書かれた2つのファイルで構成
    • rt/lib.c: インラインアセンブリベースのライブラリルーチン
    • rt/_start.c: プログラムのエントリポイント _start()

サンプルプログラム

  • examples/hello.c: テキストを 0xB8000 メモリへ直接出力
  • examples/sinwave.c: VGAモード 0x13 でサイン波アニメーションを表示
  • examples/twinkle.c: PCスピーカーで「Twinkle Twinkle Little Star」を演奏(音の警告あり)

結論

  • SectorCは 不可能に見える目標を実現した超小型Cコンパイラ であり、
    ソフトウェア極小化と創造的な言語設計の極端な実例 を示している
  • 記事の最後はユーモラスな「何を学んだか」という選択肢で締めくくられ、
    不可能へ挑む姿勢とソフトウェア単純化の価値 を風刺的に強調している

1件のコメント

 
GN⁺ 2026-02-08
Hacker Newsのコメント
  • もしこういう実装が1980年代に存在していたら、C標準には、異なるトークンが同じ16ビット値でハッシュ衝突を起こした場合は未定義動作(UB)になる、という規則ができていた気がする。
    2000年代の最適化コンパイラなら、そういうトークンをそのままno-opに最適化してしまっていたかもしれない 😉
    • 「-wTokenHashCollisionオプションを有効にしなかっただろ! 君の無知のせいでUBが発生したんだ。仕様は完全に明確だ!」という冗談まじりの反応。
    • 現実味がありすぎて吹いた。LMAO
  • 最近自分が作ったX86-16ブートセクタCコンパイラに似て見える。
    ブートセクタゲームを作るのは本当に郷愁を誘う魔法みたいな体験だ。プログラミングが本当に楽しかった時代を思い出す。
    今のAI時代では、こういうプロジェクトがあまりにも過小評価されているのが残念。
    自分のプロジェクトへのリンク
    • うーん、記事で扱っているのは完全なCではなく、512バイトに収まるC風言語コンパイラだ。
      君のプロジェクトは、ブートセクタ向けコードを生成できるオプションがあるように見える。
      どちらも面白いけれど、共通点は「boot sector」「C」「compiler」くらいしかない。
    • 「プログラミングが本当に楽しかった時代」という言葉には共感するけれど、今ではもっと多くの人が同じことをできるようになった。
      だから、もう自分は特別じゃないという気分になる。
  • こういうプロジェクトを見ると、現代の開発がどれほどハードウェアから遠ざかったかを思い出させられる。
    私たちは抽象化を積み重ね続けていて、「Hello World」を1つ動かすだけでも200MBのnode_modulesが必要になる。
    なのに、ある人は512バイトの中にCコンパイラを収めてしまう。
    みんながブートセクタコードを書くべきだという話ではないけれど、こういうプロジェクトを読むのは本当に謙虚な気持ちにさせられる体験だ。教育的価値も大きい。
  • もしかすると、このプロジェクトの作者は私かもしれない。作る過程は本当に楽しかった!
    • 本当にすごい。自分もミニマルなCコンパイラを作っているけれど、ブートセクタに収めるのではなく、8ビットシステムを対象にしている。
      このプロジェクトは、Cの中核となる構造がどれほど単純かをよく示している。
      CがB言語から、そしてBがFortranの縮小版から発展したという点も興味深い。
    • if、while、forを単純なgotoルーチンに変えたら、どれくらい小さくなるのか気になる。
      アセンブリには結局jmpしかないわけだし。
      それと、「choose your own adventure」ではなく「chose your own adventure」と書くべきだね :)
      私はミニマリズムが大好きだ。
    • このコンパイラや「barely-C」という考え方は、ブートストラップチェーンにも使えそうだ。
      非常に小さなプラットフォーム専用バイナリから始めて、そこから徐々により複雑なツールやコンパイラを作っていく、という形だ。
      例としては、mishmashvmtcc_bootstrap_alt のプロジェクトを参照できる。
  • 美しいプロジェクトだ。ただ、タイトルには早めに2023を追加したほうがいい。
    当時の議論はこちらで行われていた。
    • ありがとう! マクロ展開版なら、
      SectorC: A C Compiler in 512 bytes - リンク - 2023年5月(コメント80件)くらいにまとめられる。
  • 昨日HNに投稿された、Claudeが2週間で2万ドルかけて作った10万行のCコンパイラと比べると面白い。
    • 面白い比較ではあるけれど、あちらはLinuxカーネルをコンパイルできて、複数アーキテクチャ向けのコードも生成できる。
      一方でこのプロジェクトが扱えるのはCの一部だけだ。
      つまり、これは完全なCコンパイラというより、Cのサブセットを扱うコンパイラだ。
      このコンパイラでコンパイルできるコードは本物のCコンパイラでもコンパイルできるが、その逆は成り立たない。
  • トークンハッシュを使って疑似シンボルテーブルを作るやり方が本当にエレガントだ。
    • 自分も以前、テストツール用のパーサを書いたときに、シンボルのハッシュ値だけで識別子を管理したことがある。
      幸い、32ビットで衝突するほど大量のシンボルは使っていなかったと願う。
    • 自分も同感だ。トークンハッシュのトリックは本当に見事。
      ちなみに、0x01e0〜0x01fdの間には21バイトの空き領域が残っている。まだ何か入れられるかもしれない ;)
  • 「atoi()が通常のテキストに対して悪いハッシュ関数のように振る舞う」という部分は興味深い。
    ただ、私の記憶ではatoi()は無効な入力に対して0を返すよう定義されていたはずだ。
  • ブートセクタ向けコンパイラにはかなり関心がある
    Linuxで実行する場合は、qemuの呼び出しをcoreaudioではなくalsaに変えればよい。
    そのためのpull requestをGitHubに送った。作者が自分の冗長なシェルスクリプトのスタイルを許容してくれれば、マージされるかもしれない。
  • 本当に素晴らしい記事だった! 以前自分が作ったブートセクタOSを思い出した。
    今こそそこにCコンパイラを追加してみる時かもしれない。
    自分のOSプロジェクトへのリンク