• 検索結果がありません。

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レジスタはスタック上 のリターン命令ポインタをポイントしているはずである。

プロセッサにとっては、リターン命令ポインタがコール元プロシージャをポイントす る必要はない。したがって、

RET

命令を実行する前に、ソフトウェア上でリターン命 令ポインタを操作することで、現行コード・セグメント内の任意のアドレスをポイン トするか(

near

リターン)、別のコード・セグメント内の任意のアドレスをポイントす る(farリターン)ことができる。このような操作では、明確に定義されたコード・エ ントリ・ポイントのみを使用し、注意して実行しなければならない。