当社では新人向けにコンピュータの基礎知識や、組み込み制御などの教育を行っています。
組み込み制御ではまだまだCやC++が使われていますが、コンピュータがどの様に動作するか、 メモリがどの様に使用されているかの知識があるとプログラムの動作に対する理解度があがり、 バグの少ないプログラムをかけるようになります。
プログラムは最終的にはアセンブラ(正しくはバイナリコード)にまで展開され、 コンピュータはそのバイナリコードで動作します。
この教育ではアセンブラによってコンピュータがどの様に動いているかを説明していきます。
アセンブラの説明の前に、CPUの構成について説明します。 説明を単純化するために、昔のCISCと呼ばれるCPUを例に説明していきます。
CPUの内部構成
制御装置
命令を解釈し、各装置へ制御信号を出す。
演算装置
加算・減算などの計算を行う。
汎用レジスタ
値の計算用のレジスタ。CPUによって数が異なる。 汎用とはいっても、特定の使われ方を想定しているものもある。
専用レジスタ
- PC(プログラムカウンタ): このポインタの指している1つ前のバイナリコードが実行中のコードとなる。
- SP(スタックポインタ): 下記バイナリコードでは esp。
- フラグレジスタ: 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 基準で扱われる。

sub esp, 4
ESP が4バイト分減少し、CPUはスタック上に int 型1つ分の領域を確保する。 この領域はまだ未初期化である。

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は元のスタックフレームに戻る。

