IA-32 インテル® アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル 上巻:基本アーキテクチャ
6-2
かって拡大し、アイテムをスタックからポップした場合はスタックは上位アドレスに 向かって縮小されることになる。
プログラムやオペレーティング・システムあるいはエグゼクティブにおいては、多数 のスタックをセットアップできる。例えば、マルチタスク・システムでは、それぞれ のタスクが別々にスタックを持つことができる。システム内に設定できるスタックの 数は、セグメントの最大数と、使用可能な物理メモリとによって制限される。
ただし、システムが多数のスタックをセットアップした場合でも、特定の時点で使用 できるスタックは
1
つ(すなわち現在のスタック)だけである。「現在のスタック」と は、SSレジスタが参照するセグメント内に格納されているスタックである。プロセッサは、あらゆるスタック操作に対して自動的に
SS
レジスタを参照する。例 えば、ESP
レジスタがメモリアドレスとして使用されている場合は、SSレジスタは現 在のスタック内のアドレスを自動的にポイントする。また、CALL、RET、PUSH、POP
、ENTER
、LEAVE
の各命令もすべて、現在のスタックに対して操作を実行する。図6-1. スタックの構造
スタックのボトム
(Initial ESP Value)
コール元プロ シージャの ローカル変数
コールされる プロシージャ に渡される パラメータ フレーム境界
EBP レジスタ ESP レジスタ リターン命令ポインタ
スタックのトップ スタック・セグメント
プッシュを行うと スタックのトップが 下位アドレスに移る。
ポップを行うと スタックのトップが 上位アドレスに移る。
EBPレジスタは、一般には スタックは16ビット幅 あるいは32ビット幅。
リターン命令ポインタを ポイントするようセット アップされる。
プロシージャ・コール、 割り込み、例外
6
6.2.1.
スタックのセットアップスタックをセットし、それを現在のスタックとして設定するには、プログラムやオペ レーティング・システムあるいはエグゼクティブは次の操作を実行しなければならな い。
1. スタック・セグメントを設定する。
2. MOV、POP、LSSのいずれかの命令を使用して、スタック・セグメントのセグメント・
セレクタをSSレジスタにロードする。
3. MOV、POP、LSSのいずれかの命令を使用して、スタックのスタックポインタを ESP
レジスタにロードする。LSS命令を使用すれば、1つの操作でSSレジスタとESPレジ スタをロードできる。
セグメント・ディスクリプタをセットアップする方法や、スタック・セグメントに対 するセグメントの制限については、『
IA-32
インテル®アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル、下巻』の第
3
章「セグメント・ディスクリプタ」を参 照のこと。6.2.2.
スタックのアライメントスタック・セグメントのスタックポインタは、スタック・セグメントの幅によって
16
ビット(ワード)境界か32
ビット(ダブルワード)境界のいずれかにアライメン トを揃えなければならない。スタック・セグメントの幅は、現行コード・セグメント のセグメント・ディスクリプタ内にあるD
フラグによってセットされる(『IA-32
インテル®アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル、下巻』の 第3
章にある「セグメント・ディスクリプタ」を参照)。PUSH
命令とPOP
命令では、プッシュ操作やポップ操作に対してスタックポインタをデクリメントしたりインク リメントする量は、Dフラグによって決まる。スタック幅が
16
ビットの場合は、ス タックポインタは16
ビットずつインクリメントまたはデクリメントされる。スタッ ク幅が32
ビットの場合は、スタックポインタは32
ビットずつインクリメントまたは デクリメントされる。16
ビット値を32
ビット幅のスタックにプッシュすると、スタッ クのアライメントのずれが発生する(つまり、スタックポインタのアライメントがダ ブルワード境界に合わなくなる)。ただし、セグメント・レジスタ(16
ビット・セグ メント・セレクタ)の内容を32
ビット幅のスタックにプッシュした場合は例外であ る。この場合は、プロセッサが自動的に、スタックポインタのアライメントを次の32
ビット境界に合わせる。プロセッサは、スタックポインタのアライメントはチェックしない。スタックポイン タのアライメントを適切に維持するためには、プロセッサ上で動作しているプログラ ム、タスク、およびシステム・プロシージャによって行う。スタックポインタのアラ
IA-32 インテル® アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル 上巻:基本アーキテクチャ
6-4
イメントが正しく行われていないと、処理能力が極端に低下するばかりでなく、場合 によってはプログラム障害が発生する。
6.2.3.
スタックアクセスにおけるアドレスサイズ属性PUSH
命令やPOP
命令などの暗黙的にスタックを使用する命令では、それぞれが16
ビットまたは32
ビットの2
つのアドレスサイズ属性を持つ。その理由は、これらの命 令が暗黙的にスタックのトップのアドレスを必ず持っており、場合によっては明示的 なメモリアドレス(例えば、PUSH Array1[EBX])も持つこともあるためである。明示 的なアドレスの属性は、現行コード・セグメントのD
フラグと、67Hのアドレス・サ イズ・プリフィックスによって決まる。スタックアクセスにおいて
SP
かESP
のどちらが使用されるかは、スタックのトップ のアドレスサイズ属性で決まる。16
ビットのアドレスサイズ属性を持つスタック操作 では、16
ビットのSP
スタック・ポインタ・レジスタを使用して、最大スタックアド レスとしてFFFFH
まで使用できる。一方、32
ビットのアドレスサイズ属性を持つス タック操作では、32
ビットのESP
レジスタを使用して、最大スタックアドレスとしてFFFFFFFFH
まで使用できる。スタックとして使用されるデータ・セグメントについてのデフォルトのアドレスサイズ属性は、セグメントのディスクリプタの
D
フラグに よって制御される。このフラグがクリアされている場合は、デフォルトのアドレスサ イズ属性は16
ビットになる。このフラグがセットされている場合は、アドレスサイズ 属性は32
ビットになる。6.2.4.
プロシージャのリンクに関する情報プロセッサには、プロシージャ間をリンクさせるために、スタック・フレーム・ベー ス・ポインタとリターン命令ポインタの
2
つのポインタがある。これらのポインタを、ソフトウェア上で標準的なプロシージャ・コール技法と共に使用すれば、プロシー ジャ間のリンクを確実にしかもコヒーレンシを損なわずに実行できる。
6.2.4.1. スタック・フレーム・ベース・ポインタ
スタックは、一般に、一連のフレームに分割される。それぞれのスタックフレームに は、ローカル変数、別のプロシージャに渡されるパラメータに加え、プロシージャの リンクに関する情報が格納される。
EBP
レジスタに格納されているスタック・フレー ム・ベース・ポインタは、コールされるプロシージャについてのスタックフレーム内 の固定参照点を示す。スタック・フレーム・ベース・ポインタを使用するために、通 常は、コールされたプロシージャは、スタックにローカル変数をプッシュする前に、ESP
レジスタの内容をEBP
レジスタにコピーする。この後、スタック・フレーム・ベー ス・ポインタを使って、スタック上に渡されたデータ構造、リターン命令ポインタ、プロシージャ・コール、 割り込み、例外
6
コールされたプロシージャによってスタックに追加されたローカル変数に容易にア クセスできる。
ESP
レジスタと同じように、EBP
レジスタも現在のスタック・セグメント(すなわち、SS
レジスタのその時点での内容によって指定されるセグメント)内のアドレスを自動 的にポイントする。6.2.4.2. リターン命令ポインタ
コールされたプロシージャの最初の命令に分岐する前に、CALL命令によって
EIP
レ ジスタ内のアドレスが現在のスタックにプッシュされる。これ以後、このアドレスは リターン命令ポインタと呼ばれ、コールされたプロシージャから戻った後にコール元 のプロシージャが実行を再開する命令をポイントする。コールされたプロシージャか ら戻ると、RET命令によってリターン命令ポインタがスタックからポップされ、EIP レジスタに戻される。そこから、コール元プロシージャの実行が再開される。プロセッサは、リターン命令ポインタの位置をトラッキングしていない。したがって、
RET
命令を発行する前に、プログラマはスタックポインタが確実にスタック上のリ ターン命令ポインタをポイントするようにしなければならない。リターン命令ポイン タをポイントするようスタックポインタをリセットするためには、通常、EBPレジス タの内容をESP
レジスタに移さなければならない。プロシージャ・コールの直後にEBP
レジスタにスタックポインタがロードされていれば、EBPレジスタはスタック上 のリターン命令ポインタをポイントしているはずである。プロセッサにとっては、リターン命令ポインタがコール元プロシージャをポイントす る必要はない。したがって、