当社では新人向けにコンピュータの基礎知識や、組み込み制御などの教育を行っています。
組み込み制御ではまだまだCやC++が使われていますが、コンピュータがどの様に動作するか、 メモリがどの様に使用されているかの知識があるとプログラムの動作に対する理解度があがり、 バグの少ないプログラムをかけるようになります。
プログラムは最終的にはアセンブラ(正しくはバイナリコード)にまで展開され、 コンピュータはそのバイナリコードで動作します。
この教育ではアセンブラによってコンピュータがどの様に動いているかを説明していきます。
アセンブラの説明の前に、CPUの構成について説明します。 説明を単純化するために、昔のCISCと呼ばれるCPUを例に説明していきます。
CPUの内部構成
制御装置
命令を解釈し、各装置へ制御信号を出す。
演算装置
加算・減算などの計算を行う。
汎用レジスタ
値の計算用のレジスタ。CPUによって数が異なる。 汎用とはいっても、特定の使われ方を想定しているものもある。
専用レジスタ
- PC(プログラムカウンタ): このポインタの指している1つ前の命令が実行中のコードとなる。
- SP(スタックポインタ): このアセンブラコードでは esp。
- BP(ベースポインタ):このアセンブラコードではebp。スタック上にとられた変数は[ebp-4]のようにBPからの差分で指定される。
- フラグレジスタ: CPUの状態などがビット毎に入る。
- ゼロフラグ:前回の命令の結果が0であった時に立つ
- 符号フラグ:前回の命令の結果が負の値であった時に立つ
- キャリーフラグ:前回の命令で桁あふれが発生した時に立つ
メモリ
プログラムやデータを保存する記憶領域。 特に指定がなければ、電源を切ると内容が消えるRAMを指す。
メモリは格納するデータの種類により以下のように分けられる。
- プログラム領域
- データ領域
- スタック領域
スタックとは、コンピュータがデータを一時的に格納・管理するためのデータ構造の一つで、 後入れ先出し(LIFO:Last In, First Out)という特徴を持っています。
最後に格納したデータが最初に取り出される仕組みで、 皿を重ねた山の一番上から取るイメージに近いです。
ただしプログラムでは、[ebp - 4] のように、 スタック内の位置を指定することで重ねた山の途中のデータにアクセスすることができます。
C言語プログラムとバイナリコード
以下のプログラム①をコンパイルし、アセンブラコードに変換すると②になります。
① C言語プログラム
int a;
a = 10;
a++;
② アセンブラコード
push ebp
mov ebp, esp
sub esp, 4
mov DWORD PTR [ebp-4], 10
add DWORD PTR [ebp-4], 1
mov esp, ebp
pop ebp
②で使われる命令の説明
- push:スタックに値を保存する
- mov :右の引数の値を左の引数にコピーする
- sub :引き算
- add :足し算
- pop :スタックに保存された値を取り出す
②のアセンブラコードの動作の説明
この②のアセンブラコードがどの様に動作するかをこの下に記載します。
あわせて、スタックがどの様に使われるかも記載します。

push ebp
CPUは EBP の値をスタックに書き込み、ESP を4減算する。 これにより、呼び出し元の EBP が保存される。

mov ebp, esp
ESP の値が EBP にコピーされ、新しいスタックフレームの基準が設定される。 以降、変数は [EBP-4]のようにEBP を基準として扱われる。

sub esp, 4
ESP が4バイト分減少し、CPUはスタック上に int 型1つ分の領域を確保する。この領域は変数aになる。変数aにはまだ値は入っていない。値が入っていないということは0ということではなく、何が入っている変わらないということ。

mov DWORD PTR [ebp-4], 10
CPUは即値 10 を [EBP-4] の指すアドレスのメモリに書き込む。 これにより、変数 a の値は 10 になる。
add DWORD PTR [ebp-4], 1
CPUは [EBP-4] の値を読み出し、1を加算して再び同じアドレスに書き戻す。 この結果、a の値は 11 になる。
mov esp, ebp
スタックポインタを関数開始時の位置に戻し、 変数領域を一括で解放する。

pop ebp
スタックに保存されていた呼び出し元の EBP が復元され、 CPUは元のスタックフレームに戻る。

例としたプログラム①はここまでになります。
この後にプログラムが続いていた場合、スタックフレームが最初の状態に戻っているため、変数aは使用できません。Cプログラムの変数にスコープ(有効範囲)があるのはこのようにスタック上に変数を確保している為です。
以上、簡単ですが、Cプログラムがどの様に動いているか、変数がどの様に確保されているかの説明でした。
