前回はNASMでアセンブルして、WLINKでリンクしてDOSの16ビットEXE形式の実行ファイルを作って実行できることを確認しました。昔とった何とかとは言え、忘却力の年寄りがx86のアセンブラするのはうん十年ぶりです。記憶が怪しくなってます。そこで今回はx86お得意のお兄さんお姉さん方には常識をおさらい。
※実機動作確認には以下を使用しております。
x86のメモリモデル(特に16ビット)
16ビットでアセンブラするにあたって思い出さなきゃと思ったのがメモリモデルです。この頃のx86は32ビット/64ビット切替の世界なのでメモリモデルは「フラット」一本。何もメンドイことはありませぬ。しかし、遥か太古の時代を振り返るとx86のメモリモデル、魑魅魍魎の世界?でした。
列挙すれば以下のような感じ。
-
- Tiny
- Small
- Medium
- Compact
- Large
- Huge
- Flat
年寄の昔の記憶は大分怪しくなっていても、「慣れ親しんでいた」ということで抵抗感はまったくないのですが、これを最初から覚えろと言われたら、なんだかな~。
一応、御本家マイクロソフト社の「中の人」が上記について説明している文書があったので、URLを貼り付けておきます。
Tinyモデル
ポインタ的に言うと16ビットNEARポインタのみの世界です。コードもデータもNEARのみ。さらに言えばコード・セグメントとデータ・セグメント(そしてスタック・セグメントなども)同じところを指してます。セグメントは1個だけね。よって使えるメモリ量は64Kバイト。さらに実行開始番地は0x100番地(インテル式に書けば 0100h番地)です。
ここまで書けばお分かりでしょう。古のMS-DOSの 「.COM」形式の実行モデルです。そしてこのモデルは8086の御先祖的立ち位置の8080用のOS
デジタルリサーチ社 CP/M-80
の .COM と同じです。プログラムは0x100番地スタート。0番地から0xFF番地までにはいろいろベクタとか、OSのワーク領域とかが割り当てられてました。まさにCP/M-80から「移植された」プログラム共のためのメモリモデルであったかと。知らんけど。
Smallモデル
ポインタ的に言うとやはり16ビットNEARポインタのみの世界です。ただし、コード・セグメントとデータ・セグメントが異なる領域に割り当てられている想定です。MS-DOSの「.EXE」形式の一番シンプルな実行モデルね。コード64Kバイトまで、データ64Kバイトまで。合計で128Kバイト。
Mediumモデル
「.EXE」形式は変りませぬ。ついに複数セグメントを使い始めます。このモデルではコードについてFARポインタを使うようになります。データは依然としてNEARのみなので64KバイトMAXです。FARジャンプ、FARコールできるので8086の「巨大な1Mバイト」空間をほぼほぼコードに割り当て可能。最初のころはそんなにメモリがあって、何に使うのだとか言われたとか、言われないとか。
Compactモデル
「.EXE」形式は変りませぬ。こちらはコードについてはNEARのみ。データでFARポインタを使います。ようやく64Kバイトを超えるデータを扱えるっと。でも「1セグメント=64Kバイト」という緊縛の中でね。しょっちゅう引っかかるんだ、この制限に。配列とか構造体とか1セグメント内にせよと、トホホ。
Largeモデル
「.EXE」形式は変りませぬ。ようやくコードもデータもFARポインタ(セグメント16ビット:オフセット16ビットの4バイト)です。まあ1セグメント=64Kのままだけれども。
じゃ、最初からLargeにしておけよ、という選択は無いのであります。16ビットのx86は、NEARで動いているときはキビキビと動いていても、FARになった瞬間に動きが鈍くなり、そしてメモリ効率も悪くなるんであります。
なるべく小さいメモリモデルを選択する
というのが金言。Largeなんてもったいない。
Hugeモデル
16ビットx86で、1セグメント=64Kバイトを超越して~ということで考え出されたモデルみたいです。お惚け老人は使ったことありません。とはいえハードウエアでセグメントの大きさは決まっているので、「みかけだけ64Kバイトを超越」させるためにすごい苦労してセグメントの値を操作して辻褄を合わせているモデルみたいです。よって単純なFARポインタよりもさらにオーバヘッドがデカいのだと。
Flatモデル
80386以降のCPUで使える32ビットモードを使い、1セグメントは最大4Gバイトね、という世界に入るモードです。一応、入るときにセグメントを設定しているのだけれども1セグメントしかない(フラット)な世界なのでセグメントのあった世界のことは忘れてしまえます。あのセグメントとはいったい何だったの?
32ビット化したWindows(Windows95などから)一般化するわけですが、それ以前からDOS上で動く各種のDOS Extender等で使われていたような。
ここでも拡張子は「.EXE」が使われているのですが、格納されているのは「32ビット」のコードになるので、16ビットの「.EXE」とは異なります。OSは走らせるときにどっちの方か確かめているハズ。
オマケ、WASM
OpenWatcom C/C++環境をインストールしたので、The Open Watcom Assembler、コマンド名WASMというアセンブラも自動的にインストールされてます。過去回でNASMインストールしてますが、これはFreeDOSが、CコンパイラはOpenWatcom 1.9推し、アセンブラがNASM推し、だったからです。
WASMをつらつらみるに、16/32 bitのアセンブラ(NASMは16/32/64対応)です。64ビットやらないのなら結構強力そう。特に「そそられる」部分が以下です。
オプションスイッチの中に、MASM(マイクロソフト)とTASM(ボーランド)の両巨頭の互換スイッチがあるではありませぬか。まあどこまでコンパチなんだか分からんけど。
後でWASMも使うかもですが、まあ、とりあえず予定通りNASMで行くってもんですかい。