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

IA-32 インテル ®

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

farコールを実行するときには、プロセッサは以下の動作を行う(図6-4.を参照)。 1. CSレジスタの現在値を、スタックにプッシュする。

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

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

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

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

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

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

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リターン時の

スタック コール前の

スタック・

フレーム

コール後の スタック・

フレーム

コール前の スタック・

フレーム

コール後の スタック・

フレーム

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命令を使用することで、レジスタの全部、または一部をセーブ

し、リストアすることができる。PUSHF命令は、EFLAGSレジスタの下位ワードをスタックにプッ シュし、PUSHFD命令は、レジスタ全体をスタックにプッシュする。POPF命令は、スタックから

EFLAGSレジスタの下位ワードに1ワードをポップする。POPFD命令は、スタックからレジスタに1

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

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

IA-32アーキテクチャの保護メカニズムにおいては、4つの特権レベルを認識する。特権レベルはそ

れぞれ0〜3の番号が付けられ、数が大きくなるほど特権レベルは低くなる。これらの特権レベルを 使用する最大の理由は、オペレーティング・システムの信頼性を高めることにある。たとえば、図 6-3.に、保護のリングとして見立てた場合、それぞれの特権レベルがどのように解釈できるかを示す。

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

低い特権のセグメント内にあるコード・モジュールから高い特権のセグメントで動作するモジュー ルにアクセスするには、ゲートと呼ばれる厳密に制御され保護されているインターフェイスを使用 しなければならない。保護ゲートを介さず、しかも十分なアクセス権を持たないで高い特権のセグ メントにアクセスしようとすると、一般保護例外(#GP)が発生する。

オペレーティング・システムやエグゼクティブがこのマルチレベルの保護機構を使用する場合は、

コール元プロシージャより高い特権保護レベルにあるプロシージャへのコールは、farコールと同様 の方法で処理される(6.3.2.項「farコール操作とfarリターン操作」を参照)。ただし、次の点で異なる。

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

— アクセス権に関する情報。

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

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

図6-3. 保護のリング

レベル 0

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

オペレーティング・

オペレーティング・

システムのサービス

アプリケーション

0 1 2 3

最高位 最低位

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

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

プロセッサは、コールされたプロシージャを実行するために、新しいスタックに切り替える(ス タック・スイッチ)。それぞれの特権レベルは、自身のスタックを持つ。特権レベル3のスタッ クのセグメント・セレクタとスタック・ポインタは、それぞれSSレジスタとESPレジスタに格 納され、さらに、より高い特権レベルに対するコールが発生した時点で自動的にセーブされる。

特権レベル2、1、および0の各スタックのセグメント・セレクタとスタック・ポインタは、タ スク・ステート・セグメント(TSS)と呼ばれるシステム・セグメント内に格納される。

スタック・スイッチ実行時にコール・ゲートとTSSを使用することは、一般保護例外が発生した場 合を除き、コール元プロシージャにとっては透過である。

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

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

を参照)。

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

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

図6-4. 異なる特権レベルへのコール時のスタック・スイッチ

パラメータ 1 パラメータ 2

コール前のESP コール元プロシージャの

スタック

コール後のESP

コールされるプロシージャの スタック

コール元のSS コール元のESP

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

コール元のEIP コール前の

スタック・ コール後の

スタック・

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

リターン後のESP

リターン前のESP

コール元のSS コール元のESP

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

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

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

注記:リターン時には、RET n命令のn オペランドに対して正しい値が与 えられた場合に、パラメータが両 スタック上で開放される。

フレーム

フレーム