わかるUNIXの歴史第 8 回 / よそで作って、運ぶ

第7回の宿題 ── 最初のアセンブラは、何が組んだのか

アセンブラは、何が作った? 最初の PDP-7 Unix は、じつは PDP-7 だけでは作れませんでした。別の大型機(GE-635/GECOS)でアセンブルし、結果を紙テープに穴で刻んで、物理的に PDP-7 まで運んだのです。第6回の O-code と同じ「よそで作って運ぶ」── その、いちばん泥くさい実物。

必要な道具:第6回(運ぶ)・第7回(アセンブラ) 種明かし:新しい機械は、既にある機械から立ち上げる

第7回で「最初の Unix は PDP-7 のアセンブリで書かれた」と見て、宿題を残しました ── アセンブリを機械語にするアセンブラが要るのに、その最初のアセンブラは何が組んだのか? PDP-7 には、最初アセンブラすらありません。鶏がいないのです。答えは意外なほど物理的でした。Thompson は別の機械を使ったのです。すでに立派に動いていた大型機 GE-635(OS は GECOS)で PDP-7 向けの機械語を作り、それを紙テープに刻んで PDP-7 まで持って行った。この「よその機械を借りる」やり方を、クロスアセンブルと呼びます。

01PDP-7 だけでは、始められなかった

第7回の自己ホスティングの輪 ── アセンブラが自分自身を組む ── は、いったん回り始めれば強い。でも回す前は、PDP-7 にアセンブラが1本も無い。「アセンブリを機械語にするにはアセンブラが要るのに、そのアセンブラを機械語にするアセンブラが無い」。第0回の鶏と卵、そのものです。Thompson の解は、この機械の中で解こうとしないことでした。

02クロスアセンブル ── host と target は、別でいい

ふつう「アセンブラで組む」と言うと、同じ機械の上で、その機械向けの機械語を作る(ネイティブ)。でも、アセンブラを動かす機械(host)と、機械語を向ける機械(target)は、別々でかまわない。GE-635 の上で動くアセンブラ(GEMAP のマクロ)が、PDP-7 向けの機械語を吐く ── これがクロスです。下の図で、ネイティブとクロスを切り替えて、なぜ最初はクロスしかなかったかを見てください。

図1:ネイティブ vs クロス。ネイティブは host=target(同じ機械)。だが生まれる前の PDP-7 にはアセンブラが無く始められない。クロスは host≠target ── 既に動く GE-635 を借りて PDP-7 向けを作る

03紙テープで運ぶ ── 「運搬」は徒歩だった

クロスでできた PDP-7 向けの機械語は、GE-635 の中にあります。これを PDP-7 へ移さねばならない。ネットワークなどない時代です。どうしたか ── 紙テープに穴を開けて出力し、そのテープを手に持って PDP-7 まで歩いて運び、読み取り機に通した。第6回で「O-code を新マシンへ運ぶ」と言った、あの「運ぶ」の正体が、この穴あきテープの徒歩搬送です。下の図で、その一連を動かしてみてください。

図2:クロスアセンブル→紙テープ→PDP-7。GE-635 で PDP-7 向け機械語を作り、紙テープに穴で刻み、物理的に運び、PDP-7 が読んで実行する。やがて PDP-7 は自前アセンブラを持ち、GECOS を卒業する
GE-635(GECOS)で PDP-7 向けの機械語を用意。「▶」で、紙テープに刻んで運び、PDP-7 で動かすまでを再生。
今回の急所 ── 新しい機械は、既にある機械から立ち上げる

クロスの発想はこうです ── 「target で target を作らなくていい。動く host を1台借りればいい」。鶏がいない新機種でも、よその鶏から卵をもらえる。これは第3回の「既存の cc を借りて gcc を着火」、第6回の「O-code を運ぶ」、そして現代のクロスコンパイル(新しい CPU や組込み機器向けを、手元の PC で作る)と、まったく同じ骨格です。半世紀、ずっと使われている“新機種の産声のあげ方”。

◇ ◇ ◇

04そして自立 ── GECOS を卒業する

クロスで PDP-7 に最小限の道具が載り、カーネル・エディタ・シェル・そしてアセンブラが揃うと、Unix は自分自身の上でプログラムを書きテストできるようになります(self-supporting)。Thompson は仕上げに、PDP-7 ネイティブのアセンブラを書いて、GE-635 を使うのを完全にやめました。第7回の図で点滅していた「最初の as は何が組んだ?」の答えが、ここで埋まります ── 最初の as は、GE-635 のクロスアセンブラが組んだ。輪は、よその機械から着火されたのです。

問いは1個ずれた(でも、無限には続かない)

では「その GE-635 のツールチェーンは何が作った?」── また下段送りに見えます。でも今回は少し違う。GE-635 もかつては新品で、さらに古い機械や、もっと原始的な手段から立ち上げられた。すべての“既にある機械”は、かつて新機種だった。クロスは「1つ前に立ち上がった機械」を借りる連鎖で、これは有限です。さかのぼると、いつか ── 借りる host が1台も無かった、いちばん最初の機械に着く。そこにはクロスの魔法が効きません。

つなぐ声 ── 「運ぶもの」の正体いろいろ 第6回は O-code を運び、今回は PDP-7 向け機械語を紙テープで運びました。運ぶ中身は「中間コード」でも「機械語」でもよく、媒体は紙テープでもネットワークでも構いません。共通するのは “動く host で作って、target へ渡す” という骨格ひとつ。番外編「クロスコンパイル」で、この現代版(新 CPU の立ち上げ、Canadian Cross など)を深掘りします。

05底は、もう見えている

クロスの連鎖をさかのぼると、必ず「借りる相手がいなかった最初の機械」に着きます。世界で初めてのそのコンピュータには、アセンブルしてくれる別の機械も、読み込ませる完成済みの紙テープもありません。ではその機械には、どうやっていちばん最初の命令を入れたのか? ── 次回、ついに底です。答えは、人間の手

正直な線 ── クロスは鶏と卵を“移す”だけ

(1) クロスアセンブルは鶏と卵を解決しません。「この機械の中で解く」のをやめ、別の(既に動く)機械へ問題を移すだけです。ただしその連鎖は有限で、さかのぼれば最初の機械(第9回)に底を打ちます。無限後退ではありません。

(2) GE-635/GECOS/GEMAP、紙テープ搬送、self-supporting へ移る時期などの細部は、資料により表現に幅があります(骨格=「GECOS 上のクロスアセンブラ→紙テープ→PDP-7→やがて自前アセンブラで自立」は、Ritchie 自身の回想などで一致)。(3) 図はワークフローを模式化したもので、実機の外観・操作を厳密に再現したものではありません。

練習問題(今回の話だけで解けます)
  1. クロスアセンブルとは何か。host・target の語を使って一文で。
    答えを見る
    アセンブラを動かす機械(host)と、機械語を向ける機械(target)が別であるアセンブル。例:GE-635(host)上で PDP-7(target)向けの機械語を作る。
  2. 最初の PDP-7 Unix で、GE-635 で作った機械語をどうやって PDP-7 へ移したか。
    答えを見る
    紙テープに穴で出力し、物理的に PDP-7 まで運んで読み取り機に通した。
  3. 「最初の as は何が組んだか」(第7回の宿題)の答えは。
    答えを見る
    GE-635(GECOS)上のクロスアセンブラ。それで PDP-7 に道具が揃い、やがて Thompson が PDP-7 ネイティブのアセンブラを書いて GECOS を卒業した。
  4. クロスは鶏と卵を解決するか。無限後退にならないのはなぜか。
    答えを見る
    解決せず、問題を「既に動く別の機械」へ移すだけ。だが借りる相手は「1つ前に立ち上がった機械」で連鎖は有限。さかのぼると、借りる相手がいない最初の機械(第9回)に底を打つ。

まとめよその機械で作って、紙テープで運んだ

第7回の宿題「最初のアセンブラは何が組んだか」の答えは、別の機械だった。生まれる前の PDP-7 にはアセンブラが無く、自分の中では始められない。そこで Thompson は、すでに動く大型機 GE-635(GECOS)の上でアセンブラ(GEMAP のマクロ)を動かし、PDP-7 向けの機械語を作った ── host≠target のクロスアセンブル。できた機械語は紙テープに穴で刻み、手で運んで PDP-7 に読ませた。第6回「O-code を運ぶ」の、泥くさい実物である。

やがて PDP-7 にカーネル・エディタ・シェル・アセンブラが揃い、Unix は自分の上で開発できる(self-supporting)ようになり、Thompson はPDP-7 ネイティブのアセンブラを書いて GECOS を卒業した。クロスの急所は「target で target を作らなくていい、動く host を借りればいい」── 第3回の既存 cc、現代のクロスコンパイルと同じ骨格だ。ただしこれは鶏と卵を別の(既にある)機械へ移すだけ。連鎖は有限で、さかのぼれば借りる相手がいない最初の機械に着く。── 次回、ついに底。最初の1バイトは、人間の手で入れられた。

この文書は「わかるUNIXの歴史」シリーズ第8回です。史実:Ken Thompson は最初、PDP-7 上ではなく GE-635 上の GEMAP アセンブラ用のマクロで PDP-7 のコードを記述し、GECOS 上で動くクロスアセンブラが紙テープを生成、それを PDP-7 へ運んで実行した。やがて Unix は自分自身で開発できる(self-supporting)状態になり、Thompson は GE-635 を完全に使わずに済ませるため PDP-7 ネイティブのアセンブラを書いた(Dennis Ritchie「The Evolution of the Unix Time-sharing System」などの回想に基づく)。クロスアセンブル/クロスコンパイルは、アセンブラ・コンパイラを動かす機械(host)と生成コードの対象機械(target)が異なる方式で、新機種の立ち上げ(ブートストラップ)に広く用いられる。クロスは鶏と卵を解決せず、既に動く別の機械へ移すが、連鎖は有限で最初の機械に底を打つ。GE-635/GECOS/GEMAP、搬送や自立時期の細部は資料により表現に幅がある。図はワークフローの模式化で実機の厳密な再現ではない。 ── 印刷する場合はブラウザの「印刷」から「PDF に保存」を(印刷版では図の操作とアニメ・解答は静止/非表示になります)。

印刷 / PDF 化:⌘+P(Windows は Ctrl+P)。画面では図1のボタンでネイティブ/クロスを切り替え、図2の「▶」で紙テープ搬送のワークフローを再生できます。「答えを見る」で解答が開きます。