fizzbuzz.gif こたえ
http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/shinichiro_h/20081011%231223722332
http://d.hatena.ne.jp/shinichiro_h/comment?date=20081011#c
やった解答してくださる方がいた!
それはともかく答えは
- "Fizz Buzz" と書かれた GIF (末尾に 3B ゴミがついているという意味で少し不正)
- Ruby (1.8) で書かれた Fizz Buzz
- Perl で書かれた Fizz Buzz
- ゴルフ場の z80 で書かれた Fizz Buzz
- x86 & MS-DOS の COM で書かれた Fizz Buzz
- x86 & PC/AT互換機の MBR に書くと Fizz Buzz が走る起動イメージ (だから 512B)
でした。最後のは
qemu -boot c -hda fizzbuzz.gif
で確認しました。パーティションテーブルにまともなデータ入ってないので、実際に使うとチェックとかある BIOS だと動かんかったりするかも。ぶっ壊してもいい MBR が今無いことに気付く。いやあるけど動かすのはだるい。
COM で BIOS のシステムコール呼べると気付いて、 x86 の二者でコードが共有できちゃって、なんかだいぶ空間が余ってしまったので、 z80 で FizzBuzz を適当に書いてつっこんだらちょうど良かった。
作った手順としては
横幅 34/35/39 pixels のどれか、という条件で GIF ファイルを作る。 34 だとマージンが非対称になっちゃうので 35 を使った。まぁ # が一番扱いやすいとはいえる。 Ruby/Perl で見ると、
GIF89a#バイナリ〜
という感じになる。 GIF89a は undefined symbol だけどパーサ的には OK なので、後で BEGIN{hogehoge; exit} することで実行しないようにすれば大丈夫。まぁ Ruby/Perl は簡単。
GIF の global color table に不正なインストラクションがあった。白を表現するための 0xffffff の真ん中なので調整が効かぬ。
> objdump -D -m i8086 -b binary fizzbuzz.gif ... f: 00 ff add %bh,%bh 11: ff (bad) 12: ff 21 jmp *(%bx,%di)
しょうがないので global color table を binspect で local color table にうつしかえた。でも今度は comment extension label + comment block のサイズの部分で
e: fe (bad) f: 11 43 72 adc %ax,0x72(%bp,%di)
となってたので、最初の comment block のサイズを 2B にした。そしたら valid 。
e: fe 02 incb (%bp,%si) 10: eb 04 jmp 0x16
で、その 2B のコメントの内容は、上記の通り x86 のコード部分に jump するコードにしといた。 0x10 と 0x16 の間は次のコメントブロックのサイズ情報と、あと z80 コードへの jump を埋めておいた。 z80 はここまで有害な命令が無かった。まぁゴルフ場仕様の z80 で有害な命令なんて HALT とジャンプ系くらいだろう。
で次は x86 のコード。難しい工夫はない。スタックポインタが GIF header の 'a' の部分で popa が呼ばれて狂ってるので、 DOS 窓で異常終了しちゃうのを防ぐためにスタックポインタ戻しておいたのと、あとメモリに置かれる位置が DOS だと 0x100 で起動イメージだと 0x7c00 とかなので、 call で IP 取得するよくあるテクニックでデータ置いてある位置を調整したくらい。
次は z80 。なんの工夫もないあんまゴルフされてないコード。
次はデータ。
cnt: db "00", 13, 10 fizz: db "Fizz", 13, 10 fzbz: db "Fizz" buzz: db "Buzz", 13, 10
このへんは Ruby とか Perl で valid なので特に escape とかもせず。 Ruby と Perl から見ると
GIF89a#バイナリ〜 Fizz FizzBuzz ;'\x8a';BEGIN{m=#=;print+(Fizz)[$_%3].(Buzz)[$_%5]||$_,$/for 1..100;' 1.upto(?d){|n|puts ["Fizz#{s=[:Buzz][n%5]}"][n%3]||s||n}#'; exit} __END__
とかになってるだけ。このあたりで comment block のサイズが足りなくなったので、 '\x8a' で次の comment block に送った。今考えるとエスケープせずに comment block とコードのダブルミーニングの方がかっこよかったな。
あとは comment extension を終わって、 local color table つきの image descriptor があって、で GIF の data が入る。 gimp が作ったまんまなので工夫は無し。このへんが MBR のパーティションテーブルとかぶってるという話。そんで起動イメージの magic number つっこんで終わり。
resb 512 - 2 + $$ - $ dw 0xaa55
これのせいで GIF 末尾にゴミがついちゃうのは避けられないかなぁ、と思う。いや、 513B とかにしたらいいんだろうけど、まぁそれもなぁと。あと 512B 以上にしていいなら bmp でもできる。最初は bmp でやろうと思ってたんだけどね。
感想としてはやっぱメモリ保護とか無い世界は自由だなぁということと、 512B って広いなぁと。