2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FreeDOSのDEBUGコマンドでDOS APIを叩いてHello Worldする

2
Last updated at Posted at 2025-12-06

この記事はComputer Society Advent Calendar 2025の7日目の記事です。

6日目 ← この記事 → 8日目

導入

本記事ではFreeDOSをQEMUで起動し、DEBUGコマンドを使用して文字列を画面に表示します。

使用環境は以下の通りです。

- WSL2 (Ubuntu 24.04.3 LTS)
- QEMU emulator version 8.2.2

FreeDOSとは

FreeDOSは、1980年代に開発されていたMS-DOS互換のOSで、MS-DOSの販売中止が発表された1994年に開始したOSSプロジェクトです。MS-DOS用のソフトウェアの実行のサポートなどを目的としています。

FreeDOSは、x86プロセッサのリアルモード (16bit) で動作します。リアルモードは全てのx86プロセッサの起動時の、8086互換の動作モードです。そのため、FreeDOSはx86_64でも動作します。

また、DOS APIと呼ばれるソフトウェア割り込みによるAPIを提供しています。呼び出すには、特定のレジスタに呼び出したい機能に対応した番号、他のレジスタにパラメータを設定し、ソフトウェア割り込みの命令を使用します。DOS APIのほとんどの呼び出しはINT 21h命令で呼び出されます。

21hのように後ろにhをつけた数字は16進数として扱います

DEBUGとは

DOS標準のデバッガで、debugと打つとレジスタやメモリの値の確認、16bit命令のアセンブルや実行を行うことができます。本記事ではDOS API呼び出しをするアセンブリを書いて実行するために利用します。

FreeDOSのダウンロードと起動

公式サイトのThe FreeDOS Projectからダウンロードできます。左上の FreeDOS 1.4 LiveCD が扱いやすい形式なので、こちらを取得します。

ダウンロードするとFD14BOOT.imgFD14LIVE.isoが含まれています。
readme では、通常の PC や仮想環境ではFD14LIVE.isoを使うことが推奨されていました(FD14BOOT.imgはLiveCDが利用できない環境向けの最小構成イメージ)。そのため、本記事でもFD14LIVE.isoを利用します。

次に、QEMUでisoファイルからFreeDOSを起動します。

qemu-system-x86_64 -cdrom FD14LIVE.iso

-cdrom <file> は指定したファイルを CD-ROM ドライブとして接続するオプションです。QEMU の BIOS は CD-ROM をブート対象としているため、このオプションのみでOSが起動します。

コマンドを実行すると、QEMU のウィンドウが立ち上がり、FreeDOS のブートメニューが表示されます。

boot_dos.png

"Use FreeDOS 1.4 in Live Environment mode" を選択すると、起動してプロンプトが表示されます。

Live Environment は、OSをハードディスクにインストールせず、CD-ROM からRAMにシステムイメージを読み込んで起動するモードです。このモードでは手軽にOSを動作させることができますが、ハードディスクへの書き込みはできません。

今回は小さいプログラムを書いてみるだけで永続化は不要なので Live Environment を選択しました。

DEBUGの操作の説明

DEBUGのいくつかの操作とアドレスの指定方法について説明します。

  • 起動はdebugで、-のプロンプトが出る
  • q: 終了する
  • ?: ヘルプの表示
  • r: レジスタの値を表示
    • r ax 0001のように指定すると値を直接書き換えられる
  • a <addr>: そのアドレスに16bit命令をアセンブルして書き込める
  • d <addr>: メモリのダンプ
  • e <addr>: バイト列や文字列を直接書き込む
  • u <addr>: 逆アセンブル
  • g=<addr>: 指定アドレスから実行

Microsoft DEBUG Utilityにその他の多くの機能が記載されています。

アドレス指定について

リアルモードでは、アドレスの指定はA:Bという形で行います。Aに入るのはセグメントレジスタでCS, DS, ES, SSがあります。Bは16bitのオフセットで16進数を使います。また、A:Bの物理アドレスはA * 16 + Bです。

DEBUGではセグメントレジスタを指定しない場合、a, u, gではCSがオフセットとなり、d, eDSがオフセットになります。

メモリに直接命令を書き込んで実行する

実際にDOS APIを呼び出して Hello World するプログラムを書いて実行してみます。

※ 私の場合、JISキーボードからUS配列を打つことになったので、こちらの記事を参考にしました。

-e 200 "Hello World!",0D,0A,"$"
-a
10B9:0100 mov ah, 9
10B9:0102 mov dx, 200
10B9:105 int 21
10B9:107 mov ah, 4C
10B9:109 mov al, 0
10B9:10B int 21
10B9:10D
-g=100
Hello World!

まず、e 200 "Hello World!",0D,0A,"$"00DS:0200に"Hello World!"の文字列と"$"を配置しています。最後に"$"を置く理由は文字列を出力するDOS APIがこの文字を読むまで文字列を出力するためです。

次にaCS:0100から命令を書いています。アセンブリで命令を書いて改行すると、命令が機械語に変換されてメモリに書き込まれて、次の書き込み位置から入力できるようになっています。

次にAHに09h、DXに200hを設定しています。AHは呼び出したい機能(AH=09hは文字列の出力)に対応した番号、DXは文字列を配置したアドレスのDSからのオフセットです。そして、int 21の呼び出しで文字列が表示されます。

ここで書き込むのを終わりにしてしまうとCPUはメモリの値を実行できる限り進み続けてしまうため、終了命令を置く必要があります。AHに4Chで終了機能を、ALに終了コードとして0を設定してDEBUGに制御が戻るようにします。

g=100で実行すると、Hello World! が出力されます。

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?