FreeBSD（GhostBSD）上でアセンブラでx86のちょっとしたバイナリを作成したい（それもMS-DOS向けの）

# はじめに
恒例のお断りですが、この文章の内容は、筆者が所属している会社・団体とは一切関わりがありません。いわゆる「自主的な研究の成果の発表」というものです。

題名はものすごく限定された状況になってしまっていますが、実際のところはもっと条件は緩くて、題名から想像されるよりはより多くの人の役に立つのではないかと思っています。例えばFreeBSD/GhostBSDとOSの条件がついていますが、パッケージになっていて楽だよね、くらいの理由しかありませんので、おそらくOSには縛られない話なのではないかと思います。

# 候補
## as
アセンブラと聞いて最初に思いつくのは、GASと呼ばれることもあるGNUアセンブラではないでしょうか。私のところにもインストールされています。（というか、binutilsというパッケージで入っているようです。binutilsをどういう経緯でインストールしたかは忘れましたが。）
ただし、これを何も考えずに動かすと、FreeBSD/GhostBSD向けのバイナリができるのではないかと思います。（むしろ、そうでないと困るのではないでしょうか。MS-DOS向けのバイナリを生成するのであれば、それ専用のGASが必要となるのだと思います。）それに今回は以下のようなインテル形式で扱いたいので、ちょっと今回のやりたいこととは違うかな、と[^ATT]。

	mov ax 0616
	mov ds ax
	mov ah 09
	mov dx 0002

## nasm
https://www.nasm.us/

パッケージでアセンブラを検索すると出てきます。（それに、アセンブラと聞いて最初に思いついたのは実はGASではなく、こちらでした。）こちらでは、MS-DOS向けのバイナリを作成できるようです。それにインテル形式も受け付けてくれます。
ただし、[DOSプログラムをクロス開発](https://qiita.com/yamori813/items/5b68f493a0d384c2d135)によれば

> NASMは直接EXEを作ることはできません。

とのことです。「いや、別にEXEファイルを（簡単に）作れなくても構わないけど、、、」と一瞬は思ったのですが、「今作りたいとは思っていないけど、EXEファイルを作れるのであれば後で何か良いことあるのでは」と欲が出てきました。ということで、慌ててインストールしないで、ひとまず候補としてとっておきます。

## yasm
https://yasm.tortall.net/

こちらもパッケージでアセンブラを検索すると出てきます。ただし、パッケージの説明には以下のようにありました。 

> YASM is a complete rewrite of the NASM assembler under the "new" BSD License
(some portions are currently under the GNU Lesser General Public License
(LGPL)). Yasm currently supports the x86 and AMD64 instruction sets, accepts
NASM and GAS assembler syntaxes, outputs binary, ELF32, ELF64, COFF, Mach-O
(32 and 64), RDOFF2, Win32, and Win64 object formats, and generates source
debugging information in STABS, DWARF 2, and CodeView 8 formats.

ということで[nasm](#nasm)と同様に直接EXEを作ることができないような、、、[nasm](#nasm)と違うのはライセンスで、製品に組み込む時に楽な場合があるということでしょうか。今回は自分が使うだけですから、差別化要因とはならないですね。
ひとまず[nasm](#nasm)と同順位の候補ということにしておきます。

## fasm
https://flatassembler.net/

こちらもパッケージでアセンブラを検索すると出てきます。[DOSプログラムをクロス開発](https://qiita.com/yamori813/items/5b68f493a0d384c2d135)によれば

> fasmというpkgもあって、これでもEXEファイル作れました。

とのこと。ということで、[nasm](#nasm)や[yasm](#yasm)を抜いて、現在暫定一位の候補です。

ただし、ほぼ同名のパッケージもあって、そちらと衝突するらしいのがちょっと気になります。衝突する相手はFPGAむけのasmということでfasmらしい（パッケージ名がfasm-fpga）ので、FPGAを何かする予定がなければ、そこまで気にしなくてもいいとは思いますが、、、、（ちなみにこちらのfはflatのfです。）


## jwasm
https://www.japheth.de/JWasm.html

やはりこちらもパッケージでアセンブラを検索すると出てきます。[DOSプログラムをクロス開発](https://qiita.com/yamori813/items/5b68f493a0d384c2d135)によれば

> いろいろ調べたところJWasmというMASM互換のアセンブラがありました。こちらはEXEが作れました。JWasmはOpen Watcomからフォークしたプロジェクトのようです。JWasmはFreeBSDでもpkgで用意されています。

だそうです。であれば、[fasm](#fasm)と同じ暫定一位ですね。

# 選択
最初に思いついたのは[nasm](#nasm)でしたが、EXEファイルを（簡単に）作れることから、以下の2つが有力候補となりました。
- [fasm](#fasm)
- [jwasm](#jwasm)

それぞれもうちょっと詳しく見ていきましょう。

まずは、fasmです。ウェブページに結構情報があって使いやすそうです。例も充実していますね。が、[Examples](https://flatassembler.net/examples.php)を見ると、いきなり"Fractal Explorer 64"とかあって、とってもとってもかっこいいのですが、

> size: 100 kilobytes

:scream::scream::scream:（まあ、そうなりますよね。）
とってもとってもとってもかっこいいのですが、今回の「ちょっとしたバイナリ」には当てはまりません。（私の理解できる量ではないでしょう。）

では、気を取り直してjwasmです。こちらも、同じようにウェブページに結構情報があって使いやすそうです。例も充実していますね。それに[JWasm Source Samples](https://www.japheth.de/JWasm/Samples.html)には"Hello world"が並んでいます。まさに今回の「ちょっとしたバイナリ」にぴったりの例です。ということで、jwasmをインストールすることに決めました。

# jwasmについて詳しく

pkgであっさりインストールできました。依存関係もなかったようです。では、早速例をコピペして試してみましょう。

    $ jwasm -bin -Fo DOS1.COM dos1.asm

例にあったもののコメントに書いてある通りにやっただけなので、説明は不要かと思いますが、"-bin"が「COM形式で出力せよ」、"-Fo DOS1.COM"が「DOS1.COMというファイルを出力せよ」でしょう。
 
    $ jwasm -mz -Fo DOS2.EXE dos2.asm 

こちらも同じように例にあったもののコメントの通りやっただけです。"-mz"が「EXE形式で出力せよ」でしょうね。（EXE形式の最初を無理やり見ると"MZ"で始まっているように見えることからのオプション名かと思います。）


FreeBSD向けの例もあるみたいなので、やってみましょう。

    $ jwasm -q -bin -Fo=FreeBSD1. FreeBSD1.asm
    FreeBSD1.asm(22) : Error A2106: Cannot open file: "elf32.inc" [ENOENT]
    FreeBSD1.asm(26) : Error A2209: Syntax error: elf32_header
    FreeBSD1.asm(40) : Error A2209: Syntax error: elf32_footer

あれ？elf32.incというファイルが必要なようです。elf32.incなんてどこにあるのでしょうか。例の中には無いようですし。これはグーグル先生にでも、、、、と思いましたが、落ち着いて考えると今回の目的だった「（それもMS-DOS向けの）」からは遠く離れてしまいましたね。ちょっと欲を出しすぎました。

さて、気を取り直して。
COM形式、EXE形式どちらもあっさりアセンブルできました。まあ、アセンブルなのでできることにそこまで驚きはないのですが、問題はまともなものができたかどうかです。念の為GhostBSD/FreeBSD上で確認してみましょう[^objdump]。まずはEXEファイルです。

    $ objdump -d DOS2.EXE 

「ファイル形式 msdos」と識別して、なんかいい感じに逆アセンブルしているようです。（余計なところまで逆アセンブルしているみたいですけど。）
この勢いでCOMファイルの方もやってみましょう。

    $ objdump -d DOS1.COM 
    objdump: DOS1.COM: file format not recognized

だめでした。ファイルを識別するためのヘッダ情報がないからでしょう。それでもfileコマンドだと賢く判断してくれる[^Eiffel]のですが、、、

    $ file DOS1.COM 
    DOS1.COM: COM executable for DOS

ファイルを識別するためのヘッダ情報がないのであれば、手で種別を指定すればいいですね。

    $ objdump -b binary -m i8086 -D DOS1.COM 

こうすると、それっぽく逆アセンブルしてくれました[^larged]。（EXEと同様に余計なところまでしているみたいですけど。）
めでたしめでたし。[^medetashi]

[^ATT]: ごめんなさい、ちょっと調べたら「インテル型式を受け入れない」というのは、私の思い込みでした。GASはインテル型式もそうでない型式（AT&T型式）も受け入れるようです。ただ、AT&T型式の方が主ってことみたいです。
[^objdump]: 最近のFreeBSD/GhostBSDだと以下の例をそのまま真似してもうまくいかないかもしれません。それは、普通にインストールされるのはllvmのobjdumpであり、一方ここで使っているのはGNUのobjdumpだからです。binutilsをインストールした上に、PATHの設定次第ではパスを指定して実行しないといけないかもしれません。
[^Eiffel]: 賢いのは間違いないのですが、EiffelだとみごとにRubyと間違えてくれます。
$ file time_in_japanese.e
time_in_japanese.e: Ruby script, Unicode text, UTF-8 text
[^larged]: EXEファイルの時は-dで、COMファイルの時は-Dなのは間違いではないのか、と私も思ったのですが、COMファイルで-dとやると逆アセンブルの結果を出力してくれません。大文字小文字に意味があるのだと思いますが、面倒なので調べていません^_^;
[^medetashi]: 「おい、どこがめでたいんだ！これでは、アセンブルして逆アセンブルしただけで、まるで『むすんでひらいて』みたいではないか！」ですか？まあ、ここに書いてあることだけ見ればその通りなのですが、DOS1.COMとDOS2.EXEには、ここに書いていないところでしっかり役立ってもらいました。