この章では,これまでに説明できなかった細かな事柄や,補足的な説明を行う.
CPU を実行する命令は「機械語」で指定するが,機械語は 2 進数である. 人間がその全てを指定するのは困難である.そのため,各 CPU には,人間が 簡単に理解できるような言葉(英単語) を用いて,命令を記述することができるように なっている.この言語を アセンブリ言語または,アセンブラ という. アセンブリ言語は,各 CPU 毎に異なることに注意しよう.
最小構成のコンピュータは,CPU と,実記憶から成ることは既に説明したが, その処理を指定するアセンブリ言語は,メモリとのやり取りを記述することができる ことが,大きな役割であることは理解することができよう.実は,そのやり取りを する過程で,小規模なメモリが CPU 内に存在し,計算過程での一時的な 値を格納することができる.このメモリを レジスタ(register) という. 例えば,以下のようなレジスタがある.
CPU によって,8 ビット〜128 ビットまで異なるが,固定長のレジスタを 複数持っている.最近では,32 ビットか,64 ビットをもつ CPU がほとんどである. A0 〜 A4 のように特にその用途を定めないレジスタを 汎用レジスタ という. それ以外のレジスタは,CPU でプログラムを実行する場合になんらかの用途を仮定した レジスタである.CPU によっては,汎用レジスタのみをもつものもある.
例えば,アセンブリ言語は,以下のように記述する.
load a0,3000 add a0,1 store a0,3000 load a1,3003 sub a1,1 store a1,3003
load, add, sub, store などは,CPU に受渡す命令を示し,ニーモニック という.最初に,load a0,3000 より 3000 番地(から始まる)にあるメモリ にある値を,レジスタ a0 にコピーし,add a0,1 より a0 の値に 1 を加え, store a0,3000 より演算結果を再び 3000 番地に戻す. 次の load a1,3001 からの命令も同様である.sub a1,1 は レジスタ a1 の値から 1 を引く処理を示す.この処理は,C 言語で書かれたプログラム,
i++; j--;に対応している.ただし,変数 i のアドレス(&i) を 3000 番地,変数 j の アドレス(&j) を 3003 番地とする.
load a0,3000 に対して後半の a0,3000 をオペランド(operand) という.
プログラムは,コンパイラにより機械語に翻訳し,実行することができる. 機械語は CPU によって異なるため,コンパイラは CPU によって 異なった機械語を出力しなければならない.
そのため,仮想的な計算機を設計し,さまざまな CPU 上で実行するように ソフトウエアとして用意することにより,コンパイラは,単一の機械語(仮想的な 計算機が用意する機械語)を出力するのみで,さまざまな計算機上で実行することが できるようになる.このような仮想的な計算機を 仮想機械(virtual machine) という.仮想機械は,独自のアセンブリ言語を用意している.また, 仮想機械は,プログラムの実行に必要な機能を提供するので, 「オペレーティングシステムと同等な機能を提供する」ものもあれば, 「アセンブリ言語程度」を提供するものまでさまざまである.
このような技術は,ネットワーク技術が発達し,同一のプログラムを さまざまな計算機で実行するためには,重要な技術である.ただし,短所として コンピュータの上でさらに,別の計算機を実行することになり,実行速度は遅く なることがあげられる.
仮想機械方式は,オブジェクト指向言語 Smalltalk が発表されてから 多くの言語処理系で取り入れられ,最近では,オブジェクト指向言語 Java で 取り入れられている.
重要な,データ構造の一つであるスタック(stack)は,以下のような構造 をしている.
データ(要素) を,入力する操作をプッシュ(push),出力する操作を ポップ(pop) という. より,以前にプッシュされた要素は,より最近にポップされる構造となり, LIFO(Last Input First Output) という.
第 2 章メモリ管理で説明したように,「動的メモリ割当て領域」に, 実行プログラムを割当て,プログラムを実行する.そのため,実行可能プログラムは, メモリのどの位置に置いても,実行可能な形式になっていることが重要である. この形式を再配置可能(reallocatable) という.
同じ関数,手続きに対して,複数のプロセスとして 実行可能であるためには,各関数が 再入可能(reentrant) でなければならない.これは,各関数のデータ(C 言語の場合は,自動変数) がプロセス毎に,別のスタックに積まれているためである.