
■ ESPレジスタ ■
前回はスタック領域の概念について説明しました。
関数を呼出す時に「パラメータ」を渡すのですが、そのパラメ
ータを渡す為に「スタック領域」というメモリ上の領域が使用
されるのでした。
スタック領域とは、「一時的に使用される」データを格納する
為の領域であり、積み重ねるようにしてデータアクセスが行な
われるのでした。
また、スタック領域にデータを格納する時は「push」(プッシ
ュと読みます)という命令を使用し、スタック領域からデータ
を取り出す時は「pop」(ポップと読みます)という命令を使
用する事も説明しました。
今回は、スタック領域にデータを格納&取り出す事について、
もう少しだけ説明したいと思います。
まず、もう1度スタック領域からデータを取り出しているイメ
ージを見てみましょう。
レジスタEBX
┌──────┐
pop ebx┌→│ 5 │
│ └──────┘
│
スタック領域│ │ │
├──────┤
│ 5 │
├──────┤
│ 4 │
├──────┤
│ 3 │
├──────┤
│ 2 │
├──────┤
│ 1 │
└──────┘
スタック領域からデータを取り出す命令は「pop」という命令
を使用するのでした。
上の例の場合、「pop ebx」という命令を使用しているので、
スタック領域から取り出されたデータは「EBX」レジスタに格
納されるのでした。
続けて、もう1つデータを取り出してみます。
今度も全く同じ命令を使います。
pop ebx
この命令の動作イメージは以下の様になります。
レジスタEBX
┌──────┐
pop ebx┌→│ 4 │
│ └──────┘
│
スタック領域│ │ │
├ │ ┤
│ │ │
├──────┤
│ 4 │
├──────┤
│ 3 │
├──────┤
│ 2 │
├──────┤
│ 1 │
└──────┘
スタック領域なので1番最後に入れたデータから順番にデータ
が取り出されているのが分かると思います。
ここでちょっと疑問に思われた方はいらっしゃらないでしょう
か?
アセンブラコードを見てもらってお分かり頂けたかと思います
が、スタック領域からデータを取り出す時、全く同じ命令を使
用しました。
pop ebx
同じ命令なのに1番最初にスタック領域からデータを取り出す
時は、ちゃんとスタック領域の下から5番目のデータが取り出
されました。
レジスタEBX
┌──────┐
pop ebx┌→│ 5 │
│ └──────┘
│
スタック領域│ │ │
├──────┤
│ 5 │←下から5番目が取り出され
├──────┤ ている。
│ 4 │
├──────┤
│ 3 │
├──────┤
│ 2 │
├──────┤
│ 1 │
└──────┘
レジスタEBX
★もう1度、全く同じ命令┌──────┐
pop ebx┌→│ 4 │
│ └──────┘
│
スタック領域│ │ │
├ │ ┤
│ │ │
├──────┤
│ 4 │←今度は下から4番目が取り
├──────┤ 出されている。
│ 3 │
├──────┤
│ 2 │
├──────┤
│ 1 │
└──────┘
全く同じ命令を使用したはずなのに、何故1回目と2回目とで
データが取り出される場所が異なるのでしょうか?
間違って下から5番目のデータが2度取り出されたり、また、
下から2番目や3番目のデータが取り出されたりする事はない
のでしょうか?
実は、間違ってしまわないようにインテルプロセッサはスタッ
ク領域の1番上がどこなのかを常に覚えています。
そして、このスタック領域の1番上の場所を示す為に「ESP」
レジスタという物が使用されます。
もう1度、スタック領域からデータを取り出しているイメージ
を示します。
今度は「ESP」レジスタがスタック領域の1番上を常に示して
いる事に注意しながらご覧ください。
レジスタEBX レジスタESP
┌──────┐ ┌──────┐
pop ebx┌→│ 5 │ │ │
│ └──────┘ └──┬───┘
│ │
スタック領域│ │ │ スタック領域の│
├──────┤ 1番上はここ │
│ 5 │←────────┘
├──────┤
│ 4 │
├──────┤
│ 3 │
├──────┤
│ 2 │
├──────┤
│ 1 │
└──────┘
レジスタEBX レジスタESP
★もう1度、全く同じ命令┌──────┐ ┌──────┐
pop ebx┌→│ 4 │ │ │
│ └──────┘ └──┬───┘
│ │
スタック領域│ │ │ │
├ │ ┤ │
│ │ │ スタック領域の│
├──────┤ 1番上はここ │
│ 4 │←────────┘
├──────┤
│ 3 │
├──────┤
│ 2 │
├──────┤
│ 1 │
└──────┘
「ESP」レジスタが常にスタック領域の1番上を示しています。
これによりスタック領域の1番上の方から順番に取り出す事が
出来るのです。
さて、今まで「スタック領域の1番上」という表現を使ってき
ました。
この表現にはもっと簡単に呼べるように名前が付けられていま
す。
「スタック領域の1番上」の事を「スタックポインタ」と言い
ます。
「スタックポインタ」はESPレジスタに格納されているのです
が、この「スタックポインタ」というのは実際にはメモリ上の
アドレスを示しています。
先ほど、データを取り出す時にESPレジスタが常にスタック領
域の1番上を示している事を説明しました。
これはつまり「push」命令や「pop」命令を使用する事により、
ESPレジスタに格納されているアドレス情報が自動的に加減算
されるという事です。
「ESP」レジスタに格納されている値(スタックポインタ)は
インテルプロセッサの仕様により、「pop」命令や「push」命
令を使用すると自動的に加減算されるのです。
例えば「pop ebx」という命令を使用した場合、スタック領域
からデータを取り出した後に「ESP」レジスタが自動的に4加
算されます。
「ebx」レジスタは4バイトの大きさがあるので4加算される
のです。
以下に「pop」命令の動作イメージを示します。
処理が行なわれる順に番号を振っておきます。
◆pop ebxの動作イメージ
1.スタック領域からデータを取り出す
レジスタEBX
┌──────┐
pop ebx┌→│ 5 │
│ └──────┘
│
スタック領域│ │ │
├──────┤
│ 5 │
├──────┤
│ 4 │
├──────┤
│ 3 │
├──────┤
│ 2 │
├──────┤
│ 1 │
└──────┘
2.ESP(スタックポインタ)レジスタに4加算
レジスタESP
┌──────┐
│ │←──「+4」
└──────┘
スタック領域から「データを取り出した後」に「ESP」レジス
タに4「加算」するという動作が行なわれています。
これにより、スタック領域からデータが取り出された後でも常
に「ESP」レジスタがスタック領域の1番上を示す事になりま
す。
今度は「push」命令の動作を見てみましょう。
「push」命令の場合、スタック領域に「データを格納する前」
に「ESP」レジスタが4「減算」されます。
これにより常に「ESP」レジスタがスタック領域の1番上を示
す事になります。
以下に例として「push 5」の動作イメージを示します。
処理が行なわれる順に番号を振っておきます。
◆push 5の動作イメージ
1.ESP(スタックポインタ)レジスタから4減算
レジスタESP
┌──────┐
│ │←──「−4」
└──────┘
2.スタック領域にデータを格納
push 5─┐
│
│
スタック領域│ ↓ │
├──────┤
│ 5 │
├──────┤
│ 4 │
├──────┤
│ 3 │
├──────┤
│ 2 │
├──────┤
│ 1 │
└──────┘
スタック領域に「データを格納する前に」「ESP」レジスタが
4「減算」されるという動作が行なわれています。
これにより、スタック領域にデータを格納した後でも常に「E
SP」レジスタがスタック領域の1番上を示す事になります。
今回は「スタック領域」について説明し、スタック領域にデー
タを格納&取り出す時にどんな動作が行なわれるのか見てみま
した。
ちなみに、アセンブラ言語ではパラメータが少ない場合に、ス
タック領域を使用せず、レジスタのみでパラメータを渡すよう
にする事が出来ます。
しかし、C言語等の高級言語ではレジスタのみ使用してパラメ
ータを渡すようにする事は基本的に出来ません。
何故かと言うと、コンパイラがメモリを使用するように機械語
コードを生成してしまうからです。
プロセッサから見た場合、レジスタは動作が速いですが、メモ
リは非常に動作が遅いです。
パラメータ数が少ない場合はメモリよりレジスタを使用した方
が動作が速くなるのですが、コンパライラがそこまで気をきか
せてくれる事はあまり無いのです。
これが高級言語よりアセンブラ言語を使用した方が実行速度が
速いと言われる主な原因の1つになります。
今回の説明で関数を呼出す前準備としてパラメータを渡す事が
出来るようになりました。
次回は関数を呼出す瞬間に何が行なわれるのか説明する予定で
す。