セグメンテーションでのメモリ管理について

IA-32 プロセッサには以下に挙げる2つの動作モードがある。

リアルモード
  • 8086用に書かれたプログラムを実行するモード
  • 16bitで動作する
プロテクトモード
  • メモリ管理やタスク管理、保護機能等の80386で拡張された機能を利用するためのモード
  • 32bitで動作する

今回はプロテクトモードについて特にセグメンテーションでのメモリ管理に注目して取り上げる。

プロテクトモードのメモリ管理

GDTとセグメントディスクリプタ

プロテクトモードではセグメントを用いてメモリ管理を行う。これをセグメンテーションと呼ぶ。
セグメンテーションのためにはメモリ上にGDT(Global Discriptor Table)と呼ばれるセグメントディスクリプタのテーブルを作成する必要がある。
GDTを作るタイミングはリアルモードからプロテクトモードに移行する時。
セグメントディスクリプタはメモリ上に存在するセグメントの位置を指定する。
この様子を以下の図に示す。
f:id:itto-ki:20180413011326p:plain

セグメントレジスタ

また、プロセッサにはセグメントレジスタと呼ばれるセグメントを管理するためのCS,DS,ES,FS,SSの5つのレジスタがある。
これらのレジスタを用いてGDTの中に複数個あるセグメントディスクリプタのうち、どれを使用するのかを指定する。
この様子を以下に示す。
f:id:itto-ki:20180413012838p:plain

この時、セグメントレジスタにあるデータ構造をセグメントセレクタと呼び、以下の様な構造になっている。
f:id:itto-ki:20180413015224p:plain

セグメントセレクタのindex値によって使用するセグメントディスクリプタを指定している。

アドレス指定

さて先程、GDT内のセグメントディスクリプタを用いてメモリ上に存在するセグメントの位置を指定すると書いたが、
これではセグメントの先頭アドレスしか分からない。
一方で、プログラムからは◯◯セグメントの△△番地のアドレスを指定される場合がある。
この様な場合にどうするのか。
ここでセグメントディスクリプタの構造を見てみると以下の様になっている。
f:id:itto-ki:20180413193804p:plain

注目するべきなのは以下の3つのフィールドである。

フィールド 説明
Base Address Low ベースアドレスの下位16bit
Base Address Mid ベースアドレスの中位8bit
Base Address Hi ベースアドレスの上位8bit

これら3つのフィールドを合わせて(32bitsで)ベースアドレスを表す。
プログラムからのメモリアクセスの時は、このベースアドレスとプログラムによって指定されたアドレス(これを論理アドレスと呼ぶ)から、
実際のメモリ上のアドレス(これを物理アドレスと呼ぶ)への変換作業がCPUにより行われる。
また、これによりメモリがどのようにセグメンテーションされていようと、
プログラムに対してはメモリを先頭から使用できるように見せかけることができる。

感想

前に一度理解していたつもりだったけど、ほとんど覚えてなかったので復習した。
セグメンテーションは複雑すぎる機能でLinuxでは使われていないため触れる機会もないので仕方ない。