【コラム】
コンピュータアーキテクチャの話
144 メモリの管理機構
2009/01/07
- プログラミング
- メモリ
- DRAM
- x86
- プログラム
- パイプライン
- 分岐命令
- OS
- データハザード
- 命令フェッチ
- ストールサイクル数
- 制御ハザード
- パイプラインフラッシュ
- アドレス
- NOP
- IPC
- パイプライン実行
- パイプライン処理
- デコードステージ
- 割り込み
- キャッシュ
- 例外処理
- トラップ
- Instruction Per Cycle
- アクセスタイム
- ロード
- サイクル
- オーバレイ
- ストア
- アクセス
- ローカルメモリ
- 予測
- メモリアクセス
- メインメモリ
- XOR
- 空間的局所性
- 局所性
- インデックス
- Locality
- 時間的局所性
- Spatial Locality
- キャッシュアクセス
- Full Associative Cache
- フルアソシアティブキャッシュ
- Wired OR
- ダイレクトマップ
- メモリマップ
- スラッシング
- Thrashing
- ダイレクトマップキャッシュ
- Direct Map
- OR
- AND
- セット
- キャッシュライン
- Way
- セットアソシアティブキャッシュ
- Least Recently Used
- セットアソシアティブ
- LRU
- 2次キャッシュ
- カルノーマップ
- キャッシュメモリ
- バッファレジスタ
- ストアスルー
- 64ビット
- ライトスルー
- アーキテクチャ
- ストアイン
- ライトバック
- way
- NX
- 実行サイクル数
- メモリアクセス命令
- アクセス時間
- バッファオーバフロー
- サイクル数
- ヒット率
- 実行パイプライン
- セグメント方式
- TSS
- スーパーバイザ
- 物理アドレス
- XD
- 論理アドレス
メモリ管理
初期のコンピュータは1つのプログラムを実行するだけであったが、性能が向上するにつれて、複数の人のプログラムを短い時間単位で切り替えて、見かけ上、同時並行的に実行するTime Sharing System(TSS)という使用法が出てきた。このような使い方をする場合、複数のユーザのプログラムをメモリ上において実行するのであるが、ここで問題が出てくる。
まず、それぞれのユーザは、論理的には、自分がコンピュータを占有しているのであるから、プログラムは0番地から順にメモリを使うように作られている。そうすると全員のプログラムが重なってしまい、複数のユーザのプログラムをメモリ上に置いて短時間に切り替えて実行することが出来ない。また、これを解決したとしても、ユーザAのプログラムが暴走して、ユーザBやCのプログラムの格納されているメモリ領域を書き換えてしまっては困る。
このような問題を解決する手段として考案されたのが、メモリ管理機構である。
セグメント方式のメモリ管理
すべてのプログラムが0番地から始まる問題は、プログラムが意識する番地と実際のメモリの番地とをずらせることが出来れば解決できる。
図5.1のように、プロセサは0番地をアクセスするのであるが、メモリとの間にアドレス変換機構が入っており、実際にメモリに送り出すアドレスを変えてしまうのである。プログラムAを実行する場合は、そのまま0番地で良いが、プログラムB、C、Dを実行する場合は、プロセサの0番地がそれぞれのプログラムの先頭番地を指すように足し算を行う。
このとき、プロセサが認識するプログラムのアドレスを論理アドレス(あるいは仮想アドレス)と言い、メモリのアドレスを物理アドレスという。
次にどのプログラムを実行するかはOSが選択して切り替えを行うので、ハードウェアとしては、足しこむ値を保持するレジスタと、アドレスの足し算を行う機構を追加するだけで良い。ただし、詳細に言うと、OSはプログラムAであり、アドレス変換なしで実行されて、アドレスの足しこみレジスタにプログラムB、C、…のオフセット値を書き込み、それぞれのプログラムを実行させる。ただ、書き込んだ瞬間にオフセットが有効になると暴走してしまうので、ユーザプログラムに切り替える瞬間にアドレス変換が有効になるという構造にしておく必要がある。
このような制御を行うために、近代のプロセサでは、OS実行するスーパバイザ状態と、一般のプログラムを実行するユーザ状態を持ち、ユーザ状態になるとオフセットを有効にするというような構造になっている。また、OSの実行を必要とするI/Oからの割り込みなどでは自動的にスーパバイザ状態に切り替わるようになっているのであるが、横道が長くなってしまうので、これについては、別途、稿を改めて説明することにしたい。
これでアドレスをずらす問題は解決したが、これだけではプログラムBが暴走してプログラムAの領域に書き込みを行ったり、他のプログラムのメモリを読んで情報を盗んだりというのは防止できない。これを防ぐためには、開始アドレスに加えて、そのプログラムがどれだけのメモリを使えるかという値を記憶して、その値を超えないことをチェックすれば良い。
これをブロック図で表すと図5.2のようになる。論理アドレスと許容されたLengthを比較回路でチェックし、論理アドレスがLengthより大きい場合には、アクセス違反の割り込みを上げてOSに処理を任せる。並行して、論理アドレスにOffsetを足しこんで論理アドレスを物理アドレスに変換し、アクセス違反でない場合は、この変換された物理アドレスでメモリをアクセスする。このアドレス変換の単位をセグメントと呼び、この方式をセグメント方式のメモリ管理という。
これで複数のプログラムをメモリ上にぶつかり無く配置することができ、かつ、他のプログラムの領域をアクセスするという問題も防止できるようになった。
また、このメモリ管理機構は、プロセサのセキュリティを改善するのにも使用される。インターネットでのバッファオーバフロー攻撃は、配列のサイズを超えた書き込みをチェックしていないプログラムに付け込み、配列のサイズを超えるデータを読ませてプログラムの部分にまでウイルスなどの命令データを書き込み、その命令を実行させてしまうことにより、コンピュータの制御権を奪ってしまう。
これに対して、プログラムの命令セグメントとデータセグメントを分離し、命令領域のメモリには書き込めず、データ領域のメモリの内容は命令として実行できないというようにすればバッファオーバフロー攻撃を押さえ込むことが出来る。
このため、セグメント単位に、書き込み可能とか、実行可能とかの属性を記憶し、アクセスのタイプ(読み出し、書き込み、実行)と属性をチェックして、許可されたタイプのアクセスだけを許可するという機構を設ける。そして、命令セグメントは実行可能であるが書き込みは不可、データセグメントは読み書きは可能だが、実行は不可という属性を設定してやれば良い。
当初のx86アーキテクチャではセグメントの実行の可/不可という属性を持っておらず、バッファオーバフロー攻撃に弱かったのであるが、64ビット化とともに、NX(No eXcute)とかXD(eXecute Disable)と呼ぶ実行不可の属性ビットを追加した。IntelやAMDはこの機能を新機能のようにアピールするが、コンピュータアーキテクチャの歴史から見ると、セキュリティーホールのバグを修正したという感じである。
ヘッドライン
- エンデバー、再び打ち上げを延期 - 打ち上げ待機中の39A射点へ落雷が発生[18:22 7/12]サイエンス
- 【レポート】姫路ソフト、神矢みのる氏とコラボしたロボットを発表 - デビュー戦も!?[15:38 7/10]エレクトロニクス
- Microsoft、Silverlight 3公開[11:57 7/10]プログラミング
- TI、3種類の医療用開発キットを発表 - ポータブル医療機器の開発を簡素化[11:38 7/10]エレクトロニクス
- 【コラム】イマドキのIDE事情 第60回 Swing用Eclipseプラグインの決定版! Visual Swing for Eclipse[11:38 7/10]プログラミング
- CSR、Bluetoothステレオヘッドセット用SDKを発表[11:21 7/10]エレクトロニクス
- 【ハウツー】サーバサイドJavaScriptライブラリ「Narwhal」のAPIを知る[09:00 7/10]JavaScript / CSS / HTML
- 柔軟性と堅牢性を実現するウインドリバーのRTOS向けハイパーバイザ[09:00 7/10]エレクトロニクス
- ジュンク堂書店、池袋本店にて「CakePHP Cafe LiveTalk」開催[09:00 7/10]プログラミング
- 【コラム】ITエンジニア "起業"という名の選択肢 第7回 Webコンテンツプロバイダーへ方向転換してみたけれど……[08:30 7/10]システム開発ジャーナル









