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

IA-32 インテル ®

6.5.1. ENTER 命令

ENTER命令は、ブロック構造言語において広く使用されている有効範囲規則(スコープ・ルール)

と互換性があるスタック・フレームを作成する。ブロック構造言語では、プロシージャの有効範囲 は、プロシージャがアクセスできる変数のセットである。有効範囲に対する規則は、言語によって 異なる。これらの規則としては、プロシージャのネスト構造をベースとするもの、個別にコンパイ ルされるファイルへのプログラムの分割をベースとするもの、その他のモジュール化スキームを ベースとするものなどがある。

ENTER命令は、2つのオペランドを持つ。第1のオペランドには、現在コールされているプロシー ジャについてスタックに確保される動的記憶領域をバイト数で指定する。動的記憶領域は、プロシー ジャがコールされる際に作成される変数(自動変数とも呼ばれる)用に割り当てられるメモリであ る。第2のオペランドは、プロシージャのレキシカル・ネスト・レベル(0〜31)である。ネスト・

レベルとは、プロシージャ・コールの階層におけるプロシージャの深さである。レキシカル・レベ ルは、現在実行されているプログラムやタスクの保護特権レベルやI/O特権レベルとは無関係である。

次の例に示すENTER命令は、スタック上に2Kバイトの動的記憶領域を割り当て、このプロシージャ のスタック・フレーム内で、前の2つのスタック・フレームに対するポインタをセットアップする。

ENTER 2048,3

レキシカル・ネスト・レベルによって、前のスタック・フレームから新しいスタック・フレームに コピーするスタック・フレーム・ポインタの数が決まる。スタック・フレーム・ポインタは、プロ シージャの変数にアクセスする際に使用される1ダブルワードである。プロシージャが、他のプロ シージャの変数にアクセスする際に使用するスタック・フレーム・ポインタのセットは、ディスプ レイと呼ばれる。このディスプレイ内の最初のダブルワードは、前のスタック・フレームに対する ポインタである。LEAVE命令でこのポインタを使用して、現在のスタック・フレームを廃棄して

ENTER命令の効果を元に戻すことができる。

プロシージャに対するディスプレイを作成した後、ENTER命令は第1のパラメータで指定されたバ イト数だけESPレジスタの内容をデクリメントし、そのプロシージャに対する動的ローカル変数を 割り当てる。ESPレジスタ内のこの新しい値は、プロシージャ内のすべてのPUSH操作やPOP操作 に対するスタックのトップの初期値として機能する。

プロシージャがそのディスプレイをアドレス指定できるようにするため、ENTER命令によって、EBP レジスタはディスプレイ内の最初のダブルワードをポイントする。スタックは下方向に増えるため、

このダブルワードには実際にはディスプレイ内で最高位のアドレスが入る。EBPレジスタをベース・

レジスタとして指定するデータ操作命令においては、データ・セグメント内ではなくスタック・セ グメント内の位置を自動的にアドレス指定する。

ENTER命令は、ネスト形式と非ネスト形式の2つの方法で使用できる。レキシカル・レベルが0の

場合は、非ネスト形式が使用される。非ネスト形式では、EBPレジスタの内容がスタックにプッシュ され、ESPレジスタの内容がEBPレジスタにコピーされる。同時に、動的記憶領域を割り当てるた めにESPレジスタの内容から第1オペランドの内容が引かれる。非ネスト形式は、スタック・フレー ム・ポインタがコピーされない点でネスト形式とは異なる。ネスト形式のENTER命令は、第2オペ ランド(レキシカル・レベル)がゼロでない場合に使用される。

ENTER命令の正式な定義を、次の疑似コードで示す。STORAGEは、ローカル変数用に割り当てる

動的記憶領域のバイト数で、LEVELはレキシカル・ネスト・レベルである。

PUSH EBP;

FRAME_PTR ← ESP;

IF LEVEL > 0 THEN

DO (LEVEL − 1) times EBP ← EBP − 4;

PUSH Pointer(EBP); (* EBPがポイントするダブルワード*)

OD;

PUSH FRAME_PTR;

FI;

EBP ← FRAME_PTR;

ESP ← ESP − STORAGE;

(他のすべてのプロシージャがネストされる)メイン・プロシージャは、最高位のレキシカル・レベ ル、つまりレベル1で動作する。メイン・プロシージャがコールする最初のプロシージャは、次のレ キシカル・レベル、つまりレベル2で動作する。レベル2のプロシージャは、(コンパイラが指定す る固定位置にある)メイン・プログラムの変数にアクセスできる。レベル1の場合は、コピーの対象 となる前回のディスプレイが存在しないため、ENTER命令によってリクエストされた動的格納領域 だけがスタック上に割り当てられる。

あるプロシージャが、それより低いレキシカル・レベルにある別のプロシージャをコールする場合 は、コールされるプロシージャは、コール元の変数にアクセスできる。ENTER命令により、コール 元プロシージャのスタック・フレームへのポインタをディスプレイに配置することで、このアクセ スが可能になる。

あるプロシージャが、同じレキシカル・レベルにある別のプロシージャをコールする場合は、コール されるプロシージャにコール元の変数にアクセスさせることはできない。この場合、ENTER命令は、

すでにネストされている(自身より高いレキシカル・レベルで動作している)プロシージャを参照す るディスプレイ部分だけをコール元プロシージャからコピーする。新しいスタック・フレームには、

コール元プロシージャのスタック・フレームをアドレス指定するためのポインタは含まれない。

ENTER命令は、再入可能なプロシージャを、同じレキシカル・レベルにあるプロシージャへのコー

ルとして処理する。この場合、再入可能なプロシージャが繰り返されるたびに、そのプロシージャ の変数と、それがネストされているプロシージャの変数しかアドレス指定することはできない。再 入可能なプロシージャは、常に自身の変数についてはアドレス指定でき、以前に繰り返されたスタッ ク・フレームへのポインタは不要である。

ENTER命令は、当該プロシージャより高いレキシカル・レベルにあるプロシージャのスタック・フレー

ム・ポインタだけをコピーすることで、プロシージャが同じレキシカル・レベルの変数ではなく、それ より高いレキシカル・レベルの変数だけにアクセスすることを可能にしている(図6-6.を参照)。

ブロック構造言語では、ENTER命令で定義されたレキシカル・レベルを使用して、ネストされたプ ロシージャの変数に対するアクセスを制御する。たとえば、図6-6.において、プロシージャAがプ

図6-6. ネストされたプロシージャ

メイン(レキシカル・レベル1)

プロシージャA(レキシカル・レベル2)

プロシージャB(レキシカル・レベル3)

プロシージャC(レキシカル・レベル3)

プロシージャD(レキシカル・レベル4)

ロシージャBを、プロシージャBがプロシージャCをコールする場合、プロシージャCはメイン・

プロシージャとプロシージャAの変数にはアクセスできるが、同じレキシカル・レベルのプロシー ジャBの変数にはアクセスできない。図6-6.に示すネストされたプロシージャにおいて、変数への アクセスを定義すると次のようになる。

1. メインは、固定位置に変数を持つ。

2. プロシージャAは、メインの変数だけにアクセスできる。

3. プロシージャBは、プロシージャAとメインの変数だけにアクセスできる。プロシージャBは、

プロシージャCやプロシージャDの変数にはアクセスできない。

4. プロシージャCは、プロシージャAとメインの変数だけにアクセスできる。プロシージャCは、

プロシージャBやプロシージャDの変数にはアクセスできない。

5. プロシージャDは、プロシージャC、プロシージャA、およびメインの変数にアクセスできる。

プロシージャDは、プロシージャBの変数にはアクセスできない。

図6-7.において、メイン・プロシージャの先頭にあるENTER命令によって、メインに対して動的記 憶領域としてダブルワードが3つ作成されるが、他のスタック・フレームからポインタをコピーする ことはしない。ディスプレイ内の最初のダブルワードは、ENTER命令が実行される前にEBPレジス タにあった最後の値のコピーを保持する。2番目のダブルワードは、ENTER命令後のEBPレジスタ の内容のコピーを保持する。命令が実行された後、EBPレジスタはスタックにプッシュされた最初 のダブルワードをポイントし、またESPレジスタはスタック・フレーム内の最後のダブルワードを ポイントする。

メインがプロシージャAをコールすると、ENTER命令によって新しいディスプレイが作成される

(図6-8.を参照)。最初のダブルワードは、メインのEBPレジスタに保持されていた最後の値である。

2番目のダブルワードは、メインのスタック・フレームに対するポインタであり、メインのディスプ レイの2番目のダブルワードからコピーされたものである。これは、メインのEBPレジスタに保持 されていた最後の値のコピーでもある。プロシージャAは、メインがレベル1にあるため、メイン の変数にアクセスできる。したがって、メインが使用する動的記憶領域のベース・アドレスは、EBP レジスタ内の現在のアドレスに、メインのEBPレジスタに保存されている内容の4バイトを加えた ものになる。メインに対する動的変数はすべて、この値から正の固定オフセット位置にある。

図6-7. メイン・プロシージャに移行後のスタック・フレーム

EBP ディスプレイ

古いEBP

ESP メインのEBP

動的記憶領域