はりぼてOSアプリのメモリレイアウト

2014-02-18

OS自作入門の22日目、はりぼてOS用のアプリをC言語で書いた時のデータの取扱について。

はりぼてOSのアプリはプログラムはコードセグメント(CS)相対、データはデータセグメント(DS)相対で、0からのオフセットになっている。そのため、はりぼてOSは仮想アドレス、ページングは行ってないが、物理メモリ上で衝突することなく複数のアプリを動かすことができる。

ただそうした場合、リードオンリーのデータ(.rodata)を.text領域に置くことができなくて、書き換え可能な.dataや初期値不要の.bssと同じくデータ領域(データセグメント相対)に配置しないといけない。もっと言えば、スタックやヒープも同じくデータ領域にする必要がある。

そうしないと、例えばC言語上であるポインタに対する参照

*p = 0;

があったときに、そのポインタが指しているのがローカル変数(スタック上)かグローバル変数(データ)かヒープかということはわからなくて区別できないので、動かせなくなってしまう。

事実、はりぼてOSのアプリはデータ領域として、

  • スタック
  • データ領域(.data)
  • .bss
  • ヒープ

という順に配置している。スタックは高位から低位に、ヒープは低位から高位に伸びていく。

勝手な思い込みでリードオンリーのデータは.text領域に置くもんだと思っていたので、びっくりした。実際のところ、ROMとRAMの区別がある環境だと、不変のデータと可変のデータを分けて考えるのが普通だと思う。

また一般のOSでもプロセスをフォークしたときに、不変のデータは共有して、可変のデータだけを複製することで使用するメモリを節約する、というふうに聞いている。

OS自作本が終わった暁には、仮想アドレスとページングを実装するのが重大なテーマだと思う。1つ気になっているのは、アプリケーション側ではページテーブルで仮想アドレスから物理アドレスに変換されるのだろうけど、システムコールで仮想アドレスを渡された際に実アドレスに変換するのは手動でやらないといけないんだろうか。