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

far コール操作と far リターン操作

6.3. CALL と RET によるプロシージャのコール

6.3.2. far コール操作と far リターン操作

far

コールを実行するときには、プロセッサは以下の動作を行う(図

6-4.

を参照)。

1. CSレジスタの現在値を、スタックにプッシュする。

2. EIPレジスタの現在値を、スタックにプッシュする。

3. コールされたプロシージャを格納しているセグメントのセグメント・セレクタを、CS レジスタにロードする。

4. コールされたプロシージャのオフセットを、EIPレジスタにロードする。

5. コールされたプロシージャの実行を開始する。

far

リターンを実行するときには、プロセッサは次の動作を行う。

1. スタックのトップ値(リターン命令ポインタ)をEIPレジスタにポップする。

プロシージャ・コール、 割り込み、例外

6

2. スタックのトップ値(戻り先となるコード・セグメントのセグメント・セレクタ)を、

CSレジスタにポップする。

3. RET命令にオプション引き数のnがある場合は、パラメータをスタックから開放する

ため、n オペランドで指定されたバイト数だけスタックポインタをインクリメントす る。

4. コール元プロシージャの実行を再開する。

6.3.3.

パラメータの受け渡し

パラメータをプロシージャ間で受け渡すには、汎用レジスタを介する方法、引き数リ ストを使用する方法、スタックを利用する方法、の

3

種類の方法がある。

6.3.3.1. 汎用レジスタによるパラメータの受け渡し

プロセッサは、プロシージャ・コールに際して汎用レジスタのステートをセーブしな い。したがって、コール元プロシージャは、CALL命令を実行する前に、パラメータ を(ESPレジスタと

EBP

レジスタを除く)任意の汎用レジスタにコピーすると、コー ルされるプロシージャに最大

6

つのパラメータを渡すことができる。コールされたプ

図6-2. nearコールとfarコールでのスタック パラメータ 1

パラメータ 2

コール前のESP nearコール時の

スタック far

コール時の スタック

コール元のCS パラメータ 1 パラメータ 2

コール元のEIP パラメータ 3 パラメータ 3

リターン後のESP

コール元のCS パラメータ 1 パラメータ 2

コール元のEIP パラメータ 3 パラメータ 1

パラメータ 2 パラメータ 3

注記: nearリターンまたはfarリターン時には、

コール元のEIP コール後のESP

nearリターン時の スタック

コール元のEIP

RET n 命令の n オペランドに対して正しい 値が与えられた場合に、パラメータが スタックから開放される。

リターン前のESP

コール前のESP コール後のESP

リターン前のESP リターン後のESP farリターン時の

スタック コール前の

スタック フレーム

コール後の スタック フレーム

コール前の スタック フレーム

コール後の スタック フレーム

IA-32 インテル® アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル 上巻:基本アーキテクチャ

6-8

ロシージャも同様に、汎用レジスタを介してコール元プロシージャにパラメータを返 すことができる。

6.3.3.2. スタックによるパラメータの受け渡し

多数のパラメータをコールされるプロシージャに渡す場合は、コール元プロシージャ のスタックフレーム内のスタック上にパラメータを配置できる。このとき、(

EBP

レ ジスタ内にある)スタックフレームのベースポインタを使用してフレーム境界を設定 すれば、パラメータへのアクセスが容易になる。

また、コールされたプロシージャからコール元プロシージャにパラメータを返す際に も、スタックを使用できる。

6.3.3.3. 引き数リストによるパラメータの受け渡し

多数のパラメータ(またはデータ構造)をコールされるプロシージャに渡すもう

1

つ の方法として、メモリ上のいずれかのデータ・セグメントにある引き数リストにパラ メータも配置できる。この後、汎用レジスタまたはスタックを介して、引き数リスト に対するポインタをコールされたプロシージャに渡すことができる。また、同じ方法 で、コール元プロシージャにパラメータを返すことができる。

6.3.4.

プロシージャのステート情報のセーブ

プロセッサは、プロシージャ・コールに際して汎用レジスタ、セグメント・レジスタ、

EFLAGS

レジスタのいずれの内容もセーブしない。したがって、コール元プロシー

ジャは、リターン後に実行を再開するにあたって必要な汎用レジスタの値を明示的に セーブしなければならない。これらの値は、スタック上、あるいはメモリ上のいずれ かのデータ・セグメントにセーブできる。

PUSHA

命令や

POPA

命令を使用すれば、汎用レジスタの内容を容易にセーブしリスト

アすることができる。

PUSHA

命令は、すべての汎用レジスタ内の値をスタックにプッ シュする。プッシュする順序は、EAX、ECX、EDX、EBX、ESP(PUSHA命令を実行 する前の値)、

EBP、 ESI、 EDI

である。これに対し、

POPA

命令は、

PUSHA

命令でセー ブしたすべてのレジスタ値(ESI値を除く)を、スタックからそれぞれの対応するレ ジスタにポップする。

コールされたプロシージャにおいて、いずれかのセグメント・レジスタのステートが 明示的に変更された場合は、コール元プロシージャへのリターンを実行する前に、そ れらの値を元の値にリストアしなければならない。

コール元プロシージャが

EFLAGS

レジスタのステートを保持しておく必要がある場合 には、

PUSHF/PUSHFD

命令と

POPF/POPFD

命令を使用することで、レジスタの全部、

プロシージャ・コール、 割り込み、例外

6

または一部をセーブし、リストアすることができる。

PUSHF

命令は、

EFLAGS

レジス タの下位ワードをスタックにプッシュし、

PUSHFD

命令は、レジスタ全体をスタック にプッシュする。

POPF

命令は、スタックから

EFLAGS

レジスタの下位ワードに

1

ワー ドをポップする。

POPFD

命令は、スタックからレジスタに

1

ダブルワードをポップす る。

6.3.5.

他の特権レベルに対するコール

IA-32

アーキテクチャの保護メカニズムにおいては、

4

つの特権レベルを認識する。特

権レベルはそれぞれ

0

3

の番号が付けられ、数が大きくなるほど特権レベルは低く なる。特権レベルを使用する理由は、オペレーティング・システムの信頼性を高める ことにある。例えば、図

6-3.

に、保護のリングとして見立てた場合、それぞれの特権 レベルがどのように解釈できるかを示す。

この例では、最高の特権レベル

0(図の中央)が、システム内の最も重要なコード・

モジュール(通常は、オペレーティング・システムのカーネル)を格納しているセグ メントに対して使用されている。外側のリング(外にいくほど特権は小さくなる)に 行くほど、重要度が低いソフトウェアのコード・モジュールを格納しているセグメン トになる。

低い特権のセグメント内にあるコード・モジュールから高い特権のセグメントで動作 するモジュールにアクセスするには、ゲートと呼ばれる厳密に制御され保護されてい

図6-3. 保護のリング レベル 0

レベル 1 レベル 2 レベル 3 保護のリング

オペレーティング・

オペレーティング・

システムのサービス

アプリケーション

0 1 2 3

最高位 最低位

特権レベル システムのカーネル

(デバイスドライバなど)

IA-32 インテル® アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル 上巻:基本アーキテクチャ

6-10

るインターフェイスを使用しなければならない。保護ゲートを介さず、しかも十分な アクセス権を持たないで高い特権のセグメントにアクセスしようとすると、一般保護 例外(

#GP

)が発生する。

オペレーティング・システムやエグゼクティブがこのマルチレベルの保護機構を使用 する場合は、コール元プロシージャより高い特権保護レベルにあるプロシージャへの コールは、

far

コールと同様の方法で処理される(

6.3.2.

項「

far

コール操作と

far

リター ン操作」を参照)。ただし、次の点で異なる。

・ CALL

命令で与えられるセグメント・セレクタは、コール・ゲート・ディスクリプ タと呼ばれる特殊なデータ構造を参照する。コール・ゲート・ディスクリプタは、

次の内容を保持している。

- アクセス権に関する情報

- コールされるプロシージャのコード・セグメントのセグメント・セレクタ

- コード・セグメントに対するオフセット(すなわち、コールされるプロシージャの命令 ポインタ)

プロセッサは、コールされたプロシージャを実行するために、新しいスタックに 切り替える(スタックスイッチ)。それぞれの特権レベルは、自身のスタックを持 つ。特権レベル

3

のスタックのセグメント・セレクタとスタックポインタは、それ ぞれ

SS

レジスタと

ESP

レジスタに格納され、さらに、より高い特権レベルに対す るコールが発生した時点で自動的にセーブされる。特権レベル

2

1

0

の各スタッ クのセグメント・セレクタとスタックポインタは、タスク・ステート・セグメン ト(

TSS

)と呼ばれるシステム・セグメント内に格納される。

スタックスイッチ実行時にコールゲートと

TSS

を使用することは、一般保護例外が発 生した場合を除き、コール元プロシージャにとっては透過である。

6.3.6.

特権レベル間のコール操作とリターン操作

より高い特権保護レベルに対してコールを実行するときには、プロセッサは次の動作 を行う(図

6-4.

を参照)。

1. アクセス権のチェック(特権チェック)を実行する。

2. SS、ESP、CS、EIPの各レジスタの現在値を一時的に内部にセーブする。