今年ももう半年ほど経つけど、自宅ではほぼプログラムの勉強しかしてないなぁ・・・
まぁいいんだけどな。
C言語からプログラムの勉強を初めた訳だけど、行く先々で情報が欲しいときに検索をかけるとKENJI’S HOMEPAGEが出てくるのだけど、ほかにもHOWTOサイトはあるんだけど、自分が欲しい情報にドンピシャに近い情報がいつも載ってるのだよね。
という事で、アセンブリ言語の教科書を買ってみたのさ。
もちろん立ち読みしてからだけど、やっぱりほしい情報が載ってた(笑)。
アセンブリの基本をやってますがいい感じです。
最近のブログを見てるとLPIC303を狙ってるのかなぁ?って思うかもしれないですが、そんな感じで、303の黒本を見たんだけど、びっくりするくらい内容が薄いので、黒本はあくまで試験の雰囲気だけで、試験範囲を自力でやるしかなさげだに。来年でもいいし。
んまあ、その話は置いておいて
今回はタイトルどおり最近疑問に思ってたことをいくつか取り上げます。
機械語って誰が作ったん?
アセンブリをやってると、機械語ってどうやって作ったんだろうとわりと前から疑問に思ってたんだけど、1と0しか分からないのに、それでマリオが動いたり、インターネットができたりするんだよ。
いったいどうやったんだろうか。
ちょこっと調べた結果を並べてみる。
・初期の計算機にはプログラムを記憶するための記憶装置がなかった。
・フォイ・ノイマンがプログラム内蔵方式の計算機を作った。
・計算機にデータをあれこれするには、どの数値がどの命令に対応してるか、何を実行するのかを 決める必要がある。
・決め方は計算機の種類ごとに異なっている。
・電気信号の High/Low 、1か0かの組合せ。
・CPU 毎に記述方法が異なる。
なんとなく見えてきた、見えてきたんだけども。
そのCPUで使える機械語を、CPUを作った人がその機械語も作ったというのが近いかもしれないのだけど、今回知りたいのはそういう事じゃないんだな。これが。
上の箇条書きを紙に書いて頭上にぶちまけたら真相が分かっちゃうとかできたらいいんだが、残念ながらそんな事できない。
おそらくノイマン型を調べれば答えが出てくるんだろうなぁとぼんやり思ったものの、そのままにしておくのも何なのでちょこっとだけ調べてみた。
ざっくりなまとめ
・アラン・チューリングのチューリングマシン
・クロード・シャノンのデジタル回路
主にこのお二方の作ったものが基礎になってると思われる。
調べてみて、コンピュータを作ったノイマンは最後の大トリのような存在なのかしら。
あとキーポイントとして面白かったのは
・ジョージ・ブールのブール代数
・コンラート・ツーゼのZuse Z3
の2つ。
ブール代数は、x ∧ x = x ∨ x = x こんなやつね。
Z3はチューリング完全というものらしいが、チューリングは概念のようで、一定の手順に従えば答えが求められるような計算は理論上すべてチューリングマシンで実行できるとされている。
ようするにコンピュータという事だろう。
バカなまとめかたしかできないけど、それほど遠からずとも思う。
調べてみた感じだと最初のコンピュータってZ3な気がするんだけど、歴史上ではENIACというものらしい。
その後継機がEDVAC
・ジョン・モークリー
・ジョン・エッカート
・ジョン・フォン・ノイマン
このお三方が作った。
2進数で、チューリングで、プログラム内蔵方式のこやつが今のコンピュータの原型みたいなもんだろう。
設置面積は45.5平方mで7,850kgらしい。でか!
んで、ここでやっとノイマン型が出てくるのだが。
ノイマン型CPU
プログラムをデータとして記憶装置に格納し、命令列を順番に読み込んで実行するコンピュータ。
日本で、コンピュータ ソフトなければ ただの箱って川柳ができたよってノイマンに聞いたらなんて言うかな。
上に出てきたENIACはプログラム内蔵型でなくて、実行する処理の内容で配線をいじって変更する必要があったらしい。EDVACはプログラムを書き換えるときはメモリを変えればOKなので、性能は落ちたけどプログラムの作成が大幅に短くなったという事らしい。
性能の違いが、戦力の決定的差ではないということか。
んで、だいぶ長い事かかったけど、ここでEDVACの機械語はどうだったのかというのが今もっとも疑問に思ってることだった。
それはEDVACの命令セットアーキテクチャによる(とおもう)。
命令セットアーキテクチャは、プロセッサに実装された命令形式を二進数のコードのセットで表現していて、そのオペコードのセットを機械語というのだ。
おおおおお、まとまった。
おまけ
機械語で適当に書いてみる
まぁ、適当に書いてみた。ってか機械語じゃねーし。
10進数で書いてるのは無視してほしい。
5ずつ増やして書いたんだけど、なんとなしにこんなもんなんだなぁ程度で。
あとはCPUによって命令だったりなんなりの数値が異なるって事だ。
x86系のCPUなら今まで書いてたアセンブリでもいいけど、その法則にしたがって数値を書いていけば解釈して実行してくれるということだろう。
あと、気になった姫。だけど
95 50 姫 SJIS
って事が調査によって分かった。
機械語の理解もちょっと進んだかな。
バイナリエディタで見えてるのはhexdumpしたものと同じだと思うけど、実行ファイルをobjdumpしたらmovの数値は何だとかは分かるので、それがx86で使える機械語だね。
その辺はシェルコードの検証のときにやったから今回はやらないぞ。
レジスタの解釈の違いで詰まってた足し算プログラムに進む、いや、戻る
結局何で悩んでたかというと、レジスタだけで数値の計算と計算結果を標準出力に表示するということがしたかったんだけどできなかった。
;足し算 tas.asm section .text global _start _start: mov ecx,3 add ecx,2 add ecx,'0' push ecx mov eax,4 mov ebx,1 mov ecx,esp mov edx,2 int 0x80 mov eax,1 mov ebx,0 int 0x80 実行結果 $ nasm -f elf tas.asm -o tas && ld -s -o out tas && ./out 5
C言語でも文字を当てて文字にする手法があったね。
バッファの出力はスタックの一番上がespレジスタに入ってるってのを利用して、計算結果をPUSHしておいて、Writeをコールして出すという方法。
espレジスタはスタックの一番上を指しているだけであって実体はメモリらしい、残念だ。
だったらメモリを指定したらどうなるのかも試したけどセグメントエラーだった(笑)
適当にやったらそうなるわな。
あとは、PUSHして放置するのはよくないみたいなので、PUSHしたらPOPしよう。
PUSHしたらPOPね。
やってないな・・・