The Grand Prize

大賞

受賞者:Sjoerd Mullender and Robbert van Renesse

引用元:https://www.ioccc.org/1984/mullender/mullender.c

審査員・作者による説明:https://www.ioccc.org/1984/mullender/hint.html

動作

顔文字 :-) が右にスクロールしていくアニメーション。

$ ./mullender
:-)
$ ./mullender
    :-)
$ ./mullender
        :-)

解説

第1回IOCCC優勝作品。IOCCCの中でも、有名な作品の1つ。

mainが関数でなく整数列として定義されている。この整数列は機械語を数字で書いたもの。C言語プログラムは、mainというシンボルが指す先にcallで飛び込んで実行し始めるので、こういう技が原理的には可能。

なおこれは、PDP-11という1980年頃のコンピュータの機械語なので、現代のマシンで直接動かすことはできない。PDP-11エミュレータを用意する必要があるだろう。[[2015/endoh3]](未執筆)や[[2018/mills]](未執筆)を使うと動作確認できる。

おそらくこの作品がきっかけで、1985年の第2回IOCCCからは、「ポータブルなコードに加点をする」というルールが追加された。


このmainの定義をPDP-11の機械語として解釈した場合の意味を簡単に説明しておく。やっていることは大まかに次の通り。

  1. 文字列データへのアドレスを計算する
  2. writeシステムコールを呼んで" :-)\b\b\b\b"を表示する(\bはバックスペース文字)
  3. ウェイトを置く
  4. 1へ戻る

これを踏まえて、要点だけ逆アセンブルしたものを読んで欲しい。なお、数字は基本的に8進数で考える。 main+064の命令によってmain+076にある即値0は文字列のアドレスに書き換えられることに注意。

# エントリポイント
main+000: 000425         BR 25           # PC+2 + 25*2(= main+054)へジャンプする(数字が8進数であることに注意)。

# 表示する文字列データ
main+043 .. main+053: "  :-)\b\b\b\b"

# 文字列データへのアドレスをR4に入れる
main+054: 010704         MOV PC, R4      # PC+2(= main+056)をR4に代入する。
main+056: 005744         TST -(R4)       # R4から2を引き、テストをする(が、テスト結果は使っていない)。R4はmain+054になる。
main+060: 162704 000011  SUB #11, R4     # R4から11を引く。R4はmain+043になる。

# システムコールのwrite(1,main+043,9)を呼ぶ
main+064: 010467         MOV R4, 6       # PC+4 + 6(つまりmain+076)のメモリにR4の値を格納する。
main+070: 012700 000001  MOV #1, R0      # R0に1を代入する
main+074: 104404         TRAP 4          # writeシステムコールを呼ぶ(第1引数はR0 = 1、つまり標準出力に書く)。
main+076: 000000         即値0           #   writeに渡す第2引数。文字列のアドレス = main+043。
main+100: 000011         即値11          #   writeに渡す第3引数。文字列の長さ = 10進数で言うと9。

# ウェイトを置く
main+102: 012702 001000  MOV #1000, R2   # R2に1000を代入する
main+106: 104455         TRAP 55         # ダミーのシステムコール(ウェイトとして使っている)。
main+110: 077202         SOB R2, 2       # R2から1を引き、その結果が0でなければPC-2*2(つまりmain+106)にジャンプする。

# ループする
main+112: 000760         BR -20          # PC+2 - 20*2の番地(= main+054)へジャンプする。

なお、PDP-11で使っていない空間にはVAX-11用の命令列が入っているらしい。 調べようと思ったら、すでに調べている人がいたのでリンクのみ掲載する。