EXEファイル(memory image file)フォーマットの解説はありますが、中身を見れば明らか。テキストで書かれているので1行づつ順にバイナリにしていくだけです。
EXE2BINの中核部分のソースです。ローディングアドレスを取り出したら1つ前のメモリブロックの後ろから必要な数のパディング(詰め物)を入れてから、3バイトのコードを1バイトづつバイナリに変換。メモリブロックの末端でチェックサムを確認しています。
さてこのツールはアセンブラ、リンカと同じプラットホームで動くように16ビットAPLとして作りますがソースをコンパイルするのはMSCVer6.0。あまりに古いコンパイラですがDOS上で動くプログラムの作成にはこれが一番手になじんでいます。ちなみに今APL開発に使っているVisualC++2015は通算VerでいうとMSCVer19.0らしいので隔世の感があります。
出来上がったツールの実行例です。usage表示とテストプログラムtest.exeを変換した状態ですが3個のメモリブロック:コード本体、初期化済文字列MSG1、MSG2がバイナリ化されています。
出来上がったバイナリファイルの後ろの方、MSG2の領域を見ると、最初の文字が0x3B7番地から始まっています。これはメモリ上に展開されると
0x800+(0x3B7/3)=0x93D
となりリンカのロケーション情報と合致します。メモリブロック最後のパディングはこれは捨ててもいいでしょう。
こうしてソースコードからダウンロードファイルまで一貫してビルドできる環境が整いました。
容易にデバッグができるのでLCD周りのドライバもさらっと書けます。文字列の出力先をLCDに変えて動作確認できました。