2007-09-11 マシン語を知らない子ども達
■マシン語を知らない子ども達
あまりも当たり前過ぎて21世紀に入ってから言葉にだしたことはあまりないのですが、当然のことながら、プログラムというのは、マシン語を理解して初めて「書ける」と言うのです。
プログラムが書ける、という状態は「マシン語が書ける」という状態の延長線上にあるべきで、マシン語を理解していないということはマシンを理解していない、つまりプログラムを理解していないのとほぼ同じだと思います。
最近はLLと呼ばれる、いわゆる軽量スクリプト言語がメインになってきていますし、僕も普段はPHPでプログラムを書くことが増えてきましたが、それでも依然として、コンピュータというのはマシン語で動くもので、プログラムというものは全てマシン語の延長上にあると思っています。
その意識がないと、たとえPHPやJavaScriptのコードを書いていても、不可解な動きをしたり、遅くなってしまったりしたときに「なぜだろう?」ということがピンとこないことになります。
まだ大学に入って無くて、趣味のプログラミングを楽しんでいる若い人たちには、ぜひマシン語を勉強してみることを勧めます。
最近は素晴らしい時代になったもので、ごく初歩的な入門はC言語のインラインアセンブリでもすることができます。
しかし本格的にマシン語で遊びたくなったら、マイコンキットやマイコンエミュレータを使うのがお勧めです。
今のCPUは複雑になりすぎていて、初心者が全ての機能を知ろうとすると膨大な時間と労力がかかります。
しかし、最終的にはそれは全て知らなければならないことですし、知っておくべきことです。
最近は、全くの文化系の女の子が、わずか数ヶ月の研修で「システムエンジニア」や「ITコンサルタント」と称してJavaのプログラムを書くような商売もあるらしいのですが、そんなときにもぜひマシン語を勉強してもらいたいと思います。マシン語が解らないと、そもそもメモリの構造やコンピュータの動作の仕組みがわからないということなので、何が問題なのかわからないことの方が多くなると思います。
どれだけデバッガやコンパイラが進化しても、その仕組みを理解していることは絶対に必要です。
筆算ができない人が電卓を使い続けたときに答えが正しいのか間違っているのかわからないのと同様、マシン語ができない人が書いたプログラムは、一見うまく動いているように見えたとしても、それは奇跡のようなバランス、自転車で言えば補助輪がついた状態で奇跡的に動いているに過ぎず、なにか未知の問題が発生したときに素早くコンピュータ内部でおきていることに直感を巡らせ、適切な処置・対応をするためにはマシン語の理解は不可欠と言って良いでしょう。
さらにいえば、マシン語よりさらに下のレイヤーである、論理回路を理解しているとさらに理想的です。
昔、マイクロコンピュータの本といえば論理回路の本を意味しました。しかし、今の若いプログラマ達は、下のような図をみても何を意味するか瞬時にわからないのではないでしょうか


コンピュータは全て論理回路の組み合わせでできています。
マシンを構成する論理要素は全て論理回路なので、論理回路を理解しないとコンピュータの動作原理を理解していないことになります。
最低でも、論理回路だけで桁上がりをサポートした加算機を作れる程度の理解はしておいて欲しいと思います。
論理回路、マシン語、C言語の3つは、現在でもあらゆるコンピュータの基礎になっているので、最低限おさえておきたいところです。
最後に参考文献をまとめておきます。
ただ読むだけでもとても面白い本ばかりです。
- 作者: 蒲地輝尚,水越康博
- 出版社/メーカー: アスキー
- 発売日: 2004/07
- メディア: 単行本
- 購入: 16人 クリック: 2,191回
- この商品を含むブログ (28件) を見る
マシン語についてとてもわかりやすく解説してあります。入門に最適です。
- 作者: ロス・P.ネルソン,富士ソフトウエア教育出版部
- 出版社/メーカー: 富士ソフトウエア
- 発売日: 1989/03
- メディア: 単行本
- 購入: 2人 クリック: 2,040回
- この商品を含むブログ (2件) を見る
現在の主流CPUであるPentiumやCoreDuoシリーズなど、全てのCPUの元祖ともいえるのが80386です。
80386を理解することは現代のCPUを理解するということであり、これを理解しないままマルチタスクOS上で動作するプログラムを書くことはほとんど自殺行為です。
しかも本書は、80386の設計者自らが書いた貴重な本で、あらゆるところにその工夫が書かれています。386以降のCPUは単に386を拡張しただけと言っても過言ではなく、その思想の完成度の高さが伺えます。
全てのプログラマに読んで欲しい本です。
80386についてはWikipediaにも解説があります。
歴代CPUの解説を眺めるのも良い勉強になるでしょう
■マシン語に関して、追記
まあ上記エントリは極論と言われるだろうことも想像して書きましたが、めずらしく「これはひどい」タグなんかをいただいたりしたので顔を真っ赤にして追記
エントリーに言及していただいたこちら2エントリに関して
木を見て森を見ず、ということばもあるからなあ : ひろ式めもちょう
二つの文章は結局のところ論旨として「コンピュータを使うのに、マシン語を理解している必要はない」と仰りたいのでしょう。
僕もそう思います。僕もブログを書いているときに論理回路を意識したりしません。
ただ、「プログラミングを仕事としているのに、マシン語を理解している必要がない」とまでは思いません。
マシン語はプログラミングの深淵であり、母であり、基礎です。すぐに理解できなくても、それを理解しているのとしていないのとでは大きな差があると思います。
それに、実は敢えて最も重要な「どの」マシン語なのか、ということについては言及しませんでした。強いて言えば80386についてだけです。
マシン語は代表的なものをどれかひとつ覚えれば、あとはそのバリエーションに過ぎないので、そこは限定しませんでした。とはいえZ80と386では雲泥の差があります。
また、ブクマコメント中で80386についての理解があまりにも得られなくて驚きました。15年間も業界を牽引する強力なアーキテクチャがあのとき考え出されたということに対して、あまりに低い評価は驚愕するしかありません。そういうことを言っている方々は普段SPARCやPowerPCを使っておられるのでしょう*1。IA-32なんてダメだというわけですね。結果的にIA-32がIA-64をも凌駕してしまったわけですが。
まあCPUや言語の設計思想を比較して、どっちが優れているか論じるのは宗教論争になってしまうので避けたいと思いますが、それぞれのプロセッサがそれなりに意味のある構造をしています。それは美しい芸術にも似たもので、その広大な世界を探訪するだけでも十分楽しめます。
ただ、結局のところ、本当にプログラムがどのように動いているか知る必要はあると思いますし、エンジンについて全く無知なプロのレーシングドライバーは存在するかもしれませんが、全く無知なメカニックがいたらそれほど恐ろしいことはないわけで。
この場合、レーシングドライバー=エンドユーザ、メカニック=プログラマーであると読み替えていただいてかまいません。
エンジンの最低限の仕組み、自動車が走り、止まり、曲がる最も基本的な仕組みを理解せず、材料の知識もなく、熱設計もサスペンションも見たことが無くて、エンジンの分解・組み立てもしたことがない人が、NC工作機械とCADソフトの前だけで自動車の全ての部分を設計するとしたら脅威というより恐怖です。そんなクルマが走るのはメタヴァースとバネキットの中だけに留めておいて欲しいものです。
前エントリでは、マシン語とアセンブリ言語の違いについては特に言及しませんでした。面倒だという以外には本質的に違いがないからです。
そういう意味ではC言語とアセンブリ言語も本質的には違いがないのですが、C言語は便利すぎるので、やっぱり修行としてはアセンブリの段階まで落として勉強してから高級言語に戻った方が良いような気がします。
マシン語は柔道で言えば受け身、合唱で言えば腹筋みたいなもので、基礎トレーニングとしてやっておくべきもので、たとえばどんな学校でも、プログラミングを教えるのにマシン語を教えない学校はないと思うのです(id:neodenjinさんも仰ってますが)。
なんでこういうエントリーを書いたのかというと、たまたま水野君と夜中に話をしていたときにさかのぼります。
「やった!TK-80で受注ゲットだぜ」
「え、なにそれ」
「先方の技術部長がうちの技術力を確認したいというので、TK-80のデモをしたんですよ」
「そしたら?」
「マシン語から理解できてるんなら安心だ、と言ってその場で契約してくれました」
「そのひとはマシン語理解してるの?」
「もうバリバリ、TK-80世代だったみたいですよ。もうかなり年配の方で」
「へー」
というような会話があり、そうだなー、やっぱりマシン語から理解してないとなー、という気分が盛り上がったから書いてみたのです。
まあそんなことは常々思っていることですし、弊社の入社試験には必ず論理回路の問題が出てくるくらい、僕はそれが大切だと思っているのですが、世の中にはマシン語を理解することにアレルギーを持つ人も多く、そういう人にこの話をすると全力で否定されたりするので、相当程度の批判はあるだろうと思っていました。マシン語要不要論も、ある種の宗教論争だと思っています。
ただ、マシン語を覚えるのは英語やLispを覚えるのに比べればとてつもなく簡単ですし、しかも役に立ちます。
最近は使わないかも知れませんが、Windowsアプリケーションのリアルタイムデバッグをするときに、デバッガがブレークポイント周辺の逆アセンブリ情報を表示してくれたりするので、そもそもマシン語(アセンブリ言語)が理解できていればそうでない場合より遙かに多くのことがわかります。
もちろん高級言語がマシン語から独立するために作られたものであることは疑う余地もありませんが、それでもコンピュータというのは易々と限界に達し、数を増やして分散化してもどうにもならない状況というのは簡単に出現します。機械を正しくしていれば、その限界を少なくとも知らない人の二倍くらい、もっと良くすれば十倍くらいは引き上げることが出来ます。
高負荷サーバプログラミングというのは結局のところスループットの勝負なので、一秒間に処理すべきリクエスト数はかなり多く、一回のリクエストをいかに短時間で終え、同時並行的に高速にまわしていくか、というところが鍵です。
386の構造を知るべき、と思うのはそれが現在のマルチタスクOSの根幹部分を成しているからです。
実際、386が登場するまでは、FreeBSDやLinuxなどは存在すらできなかったわけですし、そのセグメント構造とタスクスイッチングの原理を知ることはプロセスまたはスレッドを並列化して動作させるプログラムには特に有効です。また、今現在のOSの構造も386の頃からほとんど変わっていません。
昔と違ってコンパイラの性能があがったので、マシン語で書きなおしただけで100倍は性能が上がる、みたいなことはさすがにもうありませんが、マシン語を理解して書くとそうでない場合よりも10倍性能があがることはあるでしょう。
実際にあった話ですが、あるとき、僕が某OSベンダーで仕事をしていたころ、とある大手企業のプログラマから怒りのメールをもらったことがあります。
「あんたがセミナーで偉そうに言っていたパフォーマンスの1/100もでないぞ。このシンプルなプログラムを見て、どこをどうすれば速くなるっていうのか説明してみろ」
そして添付されてきたプロジェクトをIDEで開き、まず実行してみると、たしかに1/100の性能もでていません。1/150くらいです。
僕は300行ほどでかかれたそのC++ソースをみて、一行付け加えて、再度実行しました。
実行した結果は、従前の130倍のスピードで動くようになりました。
僕はこの開発者にメールを書きました。
「デバッグプリントは9600bpsのシリアルポート経由で表示されるので、毎フレーム表示しようとすると確実に処理速度が落ちます。
これはデバッグプリントがシリアルポートと同期する際、CPUがACKを待つまでクリティカルセクションで割り込みブロックされ、タスクスイッチされなくなるからです」
もちろん今のOSとIA-32ではCPUレベルの防護策が二重三重にめぐらされているのできちんとOSを作ればこんなことは起きません。これはこのCPUとOS特有の現象でした。ハードウェアレベルの知識がなければわからない問題です。
僕はC++のコードに一行だけ、「100回に一回だけデバッグプリントを表示」という条件判断文を付け加えただけでした。
これを突き止め、解決するのに30秒もかかりませんでした。
しかし誤解しないでいただきたいのは、僕は上記のような知識を最初から持っていたのではありません。そうなのではないかと「直感」したのです。直感が正しかったことが確認できてからカーネル開発のチームに問い合わせ、シリアルポートがらみのプログラマに確認すると、確かにACKを待つ間クリティカルセクションになっていたことが解ったのです。なぜ直感したのかというと、僕はそういうコードを検証するとき、一種の「死神の目」でコードを見るのですが、見た瞬間にオーバーヘッドになるコードというのは解るのです。それはC++のソースを上から見ながら脳内でコンパイルしているからです。
脳内コンパイルに躓く場所に来ると、そこがあやしい、というわけです。
また、最近Erlangを触ってみて、なるほどと思ったのは、CPUのタスクスイッチを使わずにプロセスを実装することで、本来のマルチタスクよりも高い性能を実現しようとしているところです。
ErlangはCPUの動作原理に精通していなければ開発されない言語だと思いますし、それが関数型言語であるというあたりも、実は重要な関連性があります。
ErlangはLLと呼ぶにはライトな感じが全くしませんけど、こんな特殊な高給言語でさえマシン語を意識することで理解が深まるわけで、CPUのタスクスイッチで実際になにが起きるか、そしてそれがどのくらいのコストになるのか知っていれば、とてもすんなりとそういう概念を受け入れられるのだと思います。
とまあ僕なりに最近マシン語について思ったことをだらだら書いてみましたが、「マシン語の知識なんて不要」と主張するひとたちは常になにかしら理由を見つけるでしょうし、これは最終的には「プログラマは何を知っておくべきか」という宗教論争でしかないと思います。
ただ、今マシン語を学ぶのは昔よりずっと簡単ですし、ずっと役に立ちます。
これほど並列処理が重用視された時代はなかったからです。並列処理や高負荷分散をやるならマシン語の知識があるに超したことはありません。
*1:僕はこのほかにR3000とSH4も使っていましたが、今は使っていません


