前回はOpenWatcomの「ビジュアルなデバッガ」wdが使えるのに悦に入りました。しかし元をたどればNASMアセンブラだけではDOSのEXE実行形式を生成できないのでリンカをゲットするためのOpenWatcomです。今回はwlinkを使ってみます。ついでにDOSのHDDイメージのマウントとファイルアクセスもね。
※実機動作確認には以下を使用しております。
DOS上で走る16bit EXE形式のアセンブル
第47回にてFreeDOS上にインストールのNASMは、16ビットから64ビットまでx86のほぼ全てをアセンブルできる強力なアセンブラです。しかしパッケージにはリンカが不在。アセンブラ単体で作成可能な、DOSのオブジェクト形式の中でもっとも簡単な .COM 形式のオブジェクトを作ってお茶を濁しました。.COMはセグメントなし、64Kオフセットだけのバイナリオブジェクトね。
第48回にてOpenWatcom C/C++ コンパイラをインストール。これによりCのソースをコンパイルできるようになっただけでなく開発に必要な各種ツール一式をGetしました。
第49回では、コンパイラパッケージ付属の「ビジュアルな」デバッガなど使い、OpenWatcomサイコーなどと呟いてます。。。
今回はようやく第47回の問題に立ち戻り、x86の16ビット・セグメンテーションを使用した「昔懐かしい」EXEファイルをアセンブル、リンクしてみたいと思います。アセンブルしてみる例題ソースは以下の「EXE版吉例Hello world.」です。
segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop mov dx, hello mov ah, 9 int 0x21 mov ax, 0x4c00 int 0x21 segment data hello: db 'Hello world.', 13, 10, '$' segment stack class=STACK resb 1024 stacktop:
上記は、微妙にインテルASM86のソースとも、マイクロソフトMASMのソースとも異なるNASM形式です。でもx86に慣れたお兄様お姉さま方には何の障害もないでしょう。ホントか?
さてNASMによるアセンブルは以下で行えます。
> nasm -f obj testexe.asm
第47回との違いが、フォーマット指定を -f obj としていることです。これにより、testexe.obj なるオブジェクトファイルが生成されます。MS-DOS伝統のオブジェクト形式のハズ。
wlinkでリンク
OpenWatcom付属のリンカ wlink は各種環境向けのオブジェクトをリンクできる強力なリンカです。ただし、コマンドラインは、ちょいクセ強です(個人の感想です。)上記のオブジェクトからEXEファイルを得るためのコマンドラインが以下に。
> wlink name test.exe format dos file testexe.obj
-
- name text.exe という部分でEXEファイルの名前を指定
- format dos という部分で、生成するファイルのフォーマットを指定。 DOSとするとDOS用のEXEが生成されます。 他にもWINDOWS, WINDOWS NT, OS2そしてDOSイクステンダ用など切替指定が可能らしいです。
- file testexe.obj という部分で、リンクするファイル名を指定してます。ここではファイルが1個だけですが、複数ある場合は、「,」区切りでファイルを列挙するみたい。
リンク完了、ちゃんとHello world.しておるみたい。
ディスアセンブラ wdis
行き掛けの駄賃、ということで OpenWatcom付属のディスアセンブラ wdis も動かしてみましたぞ。
> wdis testexe.obj
先ほどNASMでアセンブルしたオブジェクト、8086のセグメンテーションなオブジェクトになっておるようで、わしゃ嬉しいよ。
FreeDOSのディスクイメージへのアクセス
まず FreeDOS を(QEMU上で)実行している最中であれば、忘れずに
shutdown (エイリアスだけれども)
を実行しておきます。これにより、FreeDOSのディスクイメージファイルはクローズされます。クローズせずにアクセスするときっと酷いことになるのでしょう。やってないけど。
さてFreeDOSをシャットダウンして Linuxのプロンプト(QEMUをLinuxから起動していたので)にもどったら、FreeDOSのディスクイメージファイルをマウントしてFreeDOSのファイルシステムにLinuxからアクセスが可能です。
上記では、先ほど作成したサンプルプログラムのファイルをLinux側にコピーしています。
マウントの方法は以下のWikiページで語られてます。
https://en.wikibooks.org/wiki/QEMU/FreeDOS
ちょっとMS-DOSのHDDイメージのマウントは「普通のマウント」よりクセ強なのでメモっておきます。
sudo mount -t msdos -o loop,offset=32256 freedos300.img /mnt/freedos
まず、-t で設定するファイルシステムのタイプは msdos です。ここは「あたり前」か。その後 -o でオプションをつけてます。
loop、Linuxのファイルシステム上のファイルをデバイスファイルを経由してループバック接続するためのオプションのようです。本来mountは「デバイス」をマウントするものだけれども、ここではファイル上に書き込んだハードディスクイメージなので必須だと思います。なおデバイス名を指定していないので、テキトーなお名前で「よきに計らって」くれているみたい。
offset=32256、この部分はMS-DOSのFAT16のマジックナンバーなんだと思います。セクタ512バイトで63セクタ分のオフセットのところにファイルシステムアクセスのキモがおかれておるみたいです。ファイルシステム素人老人は調べる気力もなく。Wikiに書かれていた数字を鵜呑みにしてアクセスするのみ。
freedos300.imgは、FreeDOSのディスクイメージを格納してあるファイル名です。
/mnt/freedosは、事前に mkdir して作ってある マウントポイントです。
これによりFreeDOSのファイルシステムが/mnt/freedos配下でLinuxから操作できます。
終了したら忘れずに
sudo umount /mnt/freedos
大分QEMU上のFreeDOSの操作に慣れた気がする。そんな錯覚がするだけなのよ。