tech
ハッカーの遺言状──竹内郁雄の徒然苔
第14回:プログラムで一句詠む
元祖ハッカー、竹内郁雄先生による書き下ろし連載の第14回。今回のお題は「プログラムで一句詠む」。
ハッカーは、今際の際(いまわのきわ)に何を思うのか──。ハッカーが、ハッカー人生を振り返って思うことは、これからハッカーに少しでも近づこうとする人にとって、貴重な「道しるべ」になるはずです(これまでの連載一覧)。
文:竹内 郁雄
カバー写真: Goto Aki
少し前にサイボウズ・ラボの竹迫良範さんから「31バイトでつくるアセンブラプログラミング ~アセンブラ短歌の世界~」(坂井弘亮、愛甲健二、松田和樹、坂井丈泰、竹迫良範/マイナビ/2014年1月/Kindle版もあり、写真1)をいただいていたが、しばし積ん読にしてしまっていた。あの世に逝く前に読んでおかなくては思い、さっと斜め読みしたのだが、これが面白い。
いろいろなアーキテクチャとOSの上で、31バイト、しかも、ちゃんと「5・7・5・7・7」バイトで意味的に区切れるような31バイトで実行可能な、しかも「鑑賞」に耐え得るようなプログラムを書くことをとことん追求した本だ。当然、短歌は機械語(アセンブラは機械語を書くための言語)のバイト列と直接対応がつけられるアセンブラで書く。日頃真面目に(?)プログラムを書いている人からすると信じられないような遊興本だが、アセンブラの入門書みたいな仕立てにもなっている。
私は86系のCPUをほとんど知らない。30代途中から、手作りアーキテクチャのマシン(Lispマシン──Lispというちょっと奇態な、しかし私から見れば最も普通の言語に特化したマシン)ばかり相手にしていたからである。2010年に東大を定年退職したあと、ヒマになったので、そのへんに転がっているIntelマシンをLispマシンにできないかなと思い、IntelのWebページからIntel 64およびIA-32アーキテクチャの膨大なマニュアルをダウンロードしてみた。Intelマシンでも機械語の重箱の隅をつつけば、Lispマシン風に仕立てることができるかもしれないと考えたからだ。最悪でも、それまで独自マシンのために書いていたマイクロコード(第13回の写真2参照)を「なんらか」の形で移植すればいい。だが、マニュアルがなんと総計4,716ページ。いくら読まなくてもいい部分が多いとはいえ、ちょっとめげてしまった。でも、過去のしがらみを一杯背負っていて、まぁ、大変な、かつ使いにくそうなアーキテクチャだということまではわかった。
Lispマシン以前も、第6回の遺言状で言及したフリップフロップ回路がすべて個別のトランジスタなどで構成されていた24ビットマシン「TOSBAC 3400」に始まり、DECの「PDP-11」という16ビットの銘機までずっとアセンブラ(※1)ばかり使っていたので、「アセンブラ短歌」の世界の話を読んで、おお、こういう世界で遊ぶことを楽しみにしている人がまだまだたくさんいるのだと納得した。これで安心してあの世に逝ける。
というわけで、機械語では、坂井式短歌だけではなくいろいろな遊びが可能である。もちろんかなり頭を使わないといけない遊びだ。初期のころのもので一番私の記憶に残っているのが「自殺プログラム」である。PDP-11は非常に洗練された命令アーキテクチャ(命令語の体系)を持っていることで有名で、市販終了後もずっとNASAのロケットに組み込まれていたという話がある。絶対安定的に動くプログラムを敢えてほかのマシンに変える必要がなかったということらしい。
で、課題は「PDP-11の主記憶をすべて0にクリアするプログラムを書け」である。もちろん、機械語プログラムも主記憶に入っているから、走っているプログラム自身もゼロクリアしないといけない。0はPDP-11の命令語では停止(halt)を意味するので、無事オールゼロクリアした直後に、最後にクリアした番地の命令を実行するようになっていれば、ちゃんと機械は停止してくれる(※2)。まさにセルフクリーニングプログラムだ。
解答は1通りではないが、数ステップあれば十分である(※3)。銘機PDP-11に興味のある方はぜひ挑戦していただきたい。難易度はそれほど高くないが、完成したときの喜びは一入である。自分の部屋でできないことが、コンピュータの中ならできる!
通常、機械語は主記憶の中に格納されるから、プログラムで書き換え可能である。自殺プログラムはそれを利用するわけだが、主たる用途でそれが必須のコンピュータもあった。専用のディスプレイのベクトルグラフィックスの命令が実装された「GT40」というPDP-11の変種である。NTTの研究室で1970年代半ばにこれと普通のPDP-11をつないで自然言語対話システムを開発したことがある。GT40はベクトル描画命令の次の番地の数語に描画内容を書き込んでおくというアーキテクチャだった。だから、描画するたびに命令列の途中のメモリに必要な情報を書き込むのである。その書き込みの番地などを間違えると奇妙なことが起こる。
コンピュータにとっては、ある番地に書かれている情報が、ただのデータなのか命令なのか通常は区別がつかない。PDP-11はほとんどの16ビット数値が正常な命令と解釈される。だから、なにかの間違いでただのデータが命令と解釈されると、そこからの挙動はまったく予想のつかないものになる。もちろん、中にはメモリを書き換える命令と解釈されるものもある。GT40はベクトル描画マシンだから、画面上に、グリーン一色とはいえ不思議なものが描かれては消えるという動作になる。あるとき、よほど運のいいバグがあって、この「動画」が延々と、多様かつ繰り返しなく華々しく表示された。ちなみに私の書いたプログラムではない。まだ1970年代半ばのことなので、それは奇跡的なアニメーションだった! 同じようなものを再現したかったのだが、それ以降はこんな派手なものは見ることができなかった。華々しくなる前にシステム停止してしまうからだ。バグにも運の善し悪しがあるようだ。
スタックオーバーフローによるプログラム領域の書き換えなどの「悪意のあるプログラム」は、同じような原理を用いている。だから、プログラムとデータのメモリ空間を分ける、より安全なアーキテクチャ(※4)もあるわけだが、遊びにくくなることは事実だ。
しかし、人を困らせるのではなく、プログラム同士で正々堂々とプログラム領域の書き換えを競いあったらどうだ、というのが「コア戦争」である。コア(core)は、いまでいう主記憶のことで、コンピュータ黎明期にはそれがコアという小さなドーナツ型の磁石を信号線などで織り込んだもので作られていたことによる(写真2)。いまでも主記憶をコアという人がいたらその人はもう70歳を超えているはずだ。実際、コア戦争の起原は1960年代だ。
コア戦争は、1台の仮想コンピュータの主記憶に複数の機械語プログラムをランダムに配置し、それぞれを1命令ずつ同時に実行する。もちろん、誰のプログラムがどの番地のメモリに置いてあるかはわからない。プログラムをコピーしてプロセスを派生してもいいが、その分だけ、当事者の1つ1つのプロセスへの割り当て時間は減る。こうして、停止やエラーにならず一番長らく走りおおせたプログラムが勝者となる。相手のプログラムの中に爆弾(停止になる命令)を放り込むとか、生き長らえるために自分の複製を作るとか、罠を仕組んだ命令列へジャンプさせる命令を埋め込む、などなどいろいろな戦略がある。
コア戦争についてはWikipediaに解説が出ている。また、英語だが「COREWARS」はまだ生きている対戦サイトである。日本でも日経サイエンスやASCIIの紹介記事により、1980年代後半に流行ったはずだ。
話は元に戻るが、アセンブラ短歌を読んで、坂井さんたちとはまったく異なる16進俳句なるものを詠んだことを思い出した。PDP-11は16ビットマシンなのに、ダンプは8進数であった。命令語の設計が3ビットごとにうまく区分けされていたからである。たとえば、8進で「110062」とあると、最初の「1」(ここは1ビット)がバイト処理命令、次の「1」がデータ移動命令(mov)、次の「00」がレジスタ0の内容、次の「62」がレジスタ2で指される番地という意味であること、つまり「movb R0, @R2」という命令であることが一目でわかる。8進ダンプだけで機械語が読めるのである。そんなわけで私は結構長い間、8進数人間であった。
ただし、8進数で機械語が読めるだけでは不足である。言語として一人前となるためには、話せて、聞けなければならない。上の「110062」は「イイレレロニ」である。入出力をするときに頻出する「12702 177564」という2語の命令列は「イニナレニ イナナゴロシ」と大変語呂がよい。これで当時一緒に仕事をしていた奥乃博さん(元京大教授、現早大教授)たちとは十分に会話ができた。
ところが、自作アーキテクチャのLispマシンを作り出したころからは、世の中の習いに従い、16進数(9の次は10を意味するA、以下、B、C、D、E、Fと続く)を使わなければならなくなった。では、16進数ダンプをどのように話して、聞くか。16種類の数字をユニークに1文字1モーラ(1音節)で表現するのはマストである。ちょっと試行錯誤があったが、以下のように割り振った。複数候補があるものは、周囲の音との語呂合わせがいいものをテキトーに採用する。
0:レ、オ | 8:ハ、バ、ヤ |
1:イ、ト、ヒ | 9:ク |
2:ニ | A:タ、カ |
3:サ、ミ、ザ | B:ブ、ボ |
4:ヨ、シ | C:チャ |
5:ゴ、コ | D:ド |
6:ロ、ム | E:テ、ケ |
7:ナ | F:フ |
たとえば、「AAAAEEEE」は、「タカタカテケテケ」と発音するとわかりやすい。「11111111」は「ヒトヒトヒトヒト」だ。「C」を「チャ」としたのは苦心の符号化だが、語感の幅が広がった。
このLispマシンの開発は武蔵野と厚木で地域分散したベンチャー的研究だったので、離れた研究所間で電話を通してデバグ相談を行なうことも多かった。「ハニサドレにドレブニイがあるか見てくれる?」といった会話はスパイもどきと思われたに違いない。だが、ハード担当の吉田雅治君は業界共通語にならないからといって最後までこの読み方に抵抗した。単に恥ずかしかったのだと思われる。おかげで、ソフト屋は吉田君とのデバグコミュニケーションに苦労した。たとえば、動作確認のために、同じ構造だが別の個体のマシンのダンプと読み合わせ照合する(※5)ときに、とても時間がかかった。
この読み方は、話せて、聞ける言語にするだけではなく、記憶術にもなった。語呂よく読めば、10桁の16進数を2つぐらいは短期記憶に入れて、メモしたり、タイプしたりすることが簡単にできるようになったのだ。なにも揃っていない裸のマシン上でのデバッグではこれが激しく役立った。
なかなか解決しなかったバグにはこの読み方でそれなりの固有名がつき、長期記憶になった。たとえば、「ヨブドブの謎」。これは4BDB番地がときどき挙動不審な値になることであった。原因はボード上の特定のSRAMチップが電気的に弱かったことだったが、再現性がないので特定するのに大変苦労したことが思い出される。
これ以外にも、昼休みのサッカーのシャワーのときなどにフッと重要なヒントを思いつくことが多くなった。「あのフレタゴロイが怪しい!」。ま、ここだけ見れば、いかにもハッカーだ。(当時)50前のオジサンがやることではないような気もするが……。ここいらについては、一昔前の情報処理学会誌に面白おかしく書いた(※6)。
いまのところ、16進数の掛け算はまだそれほど必要なさそうだが、そのうち義務教育で九九ではなく「ふふ」が教えられるようになるだろう。そうなったときに「ふふ」(表1)ぐらいは暗記しておかないと、「やっぱり年寄りは頭が古いなぁ」と言われそうだ。おのおの方、準備怠りなきようなされませ。
最後に、工房の話を発表した箱根のプログラミングシンポジウムにて16進数で詠んだ俳句を紹介しよう。他愛のないことこの上ないが……。
8522E 964A874 67364 はこににて くろしたはなし むなさむし
8522E 964A874 18674 はこににて くろしたはなし いやむなし
D30A8 100F293 DEABC どされたば いれれふにくさ ドテカボチャ
うーむ、坂井さんたちの格調高い短歌の足元にも及ばないなぁ。では、これにてひとまず退散。(つづく)
※1:PDP-11は数世代を使い回したが、最後のほうでは機械語の意味を変更したり拡張したりするマイクロコードも書いた。このときはDEC供給の純正のマイクロアセンブラがあまりにタコで重かったので、まず自分でマイクロアセンブラを書くところから始めたものだった。
※2:実行している命令がそれを格納していた番地をクリアしても問題はない。命令語としてCPUに読み出されたあとだからである。
※3:厳密には割込み禁止にするなどのステップが最初に必要になる。
※4:ハーバードアーキテクチャ。プログラムとデータが同じメモリ空間に書かれるフォン・ノイマンアーキテクチャと区別される。
※5:「なにそれ?」「そんな前近代的なやり方してたの?」とおっしゃるかもしれないが、まさに職人工房的なやり方だったのでしょうがない。
※6:「あるマシン工房の事例──TAO/SILENTの開発」(竹内郁雄、吉田雅治、山崎憲一、天海良治/情報処理 39(4)、314-320、1998-04-15)
竹内先生への質問や相談を広く受け付けますので、編集部、または担当編集の風穴まで、お気軽にお寄せください。(編集部)
変更履歴:
2014年12月31日:「mov R0, @R2」は「movb R0, @R2」の間違いでした。お詫びして訂正いたします。ご指摘いただき、ありがとうございました。
SNSシェア