I'd like to create tiny 32-bit (i386) executables for DOS.
As a reference, here is the NASM assembly source code of my tiny 16-bit (8086) executable for DOS:
; $ nasm -o hi16.com hi16.nasm # 26 bytes.
bits 16
org 0x100
mov dx, msg ; 16-bit pointer to string.
mov ah, 9 ; Print message.
int 0x21
ret ; exit(0).
msg: db 'Hello, World!', 13, 10, '$'
Since I want to use more than 1 MiB of memory in my 32-bit DOS executables, most probably I need a DOS extender. After looking at multiple DOS extenders, I've decided to try WDOSX, which seems to have the smallest stub (.exe prefix for setting up protected mode): WDOSX.DX (see here how to get it) is just 9720 bytes. The source code of my (wannabe) tiny 32-bit DOS executable is:
; $ nasm -o hi32.exe hi32.nasm # 37+9720 bytes.
bits 32
wdosx_dx_start:
incbin "WDOSX.DX" ; ~9720 bytes.
org wdosx_dx_start-$
mov ax, 0x901
int 0x31 ; Enable virtual interrupts.
mov edx, msg ; 32-bit pointer to string.
mov ah, 9 ; Print message.
int 0x21
mov ax, 0x4c00 ; exit(0).
int 0x21
msg: db 'Hello, World!', 13, 10, '$'
Both of these executables (hi16.com and hi32.exe) work out-of-the-box in DOSBox. By using DPMI function 0x0501 my 32-bit DOS program will able to allocate memory blocks larger than 1 MiB, thus my goal is fulfilled.
My question: Is there a stub smaller than WDOSX.DX (9720 bytes) I could use? WDOSX provides many features of a DPMI 0.9 host, and I don't need most of them, e.g. I don't need support for many binary formats (e.g. LE, PE), VCPI, INT15, 32-bit DOS API (all functions), mouse API, most of the DPMI API.
The features I need:
- It has to work if there is a DPMI host (e.g. DOS window in Windows or HDPMI32.EXE running), and it has to work if XMS is available (but no v8086). I don't care about other environments, e.g. EMM386, VCPI, INT15.
- Allocate several MiB of memory.
- Upon program exit, release the allocated memory.
- Open a DOS file by name, read it, write it, close it. It's OK if I have to copy data manually between a low memory address (<1 MiB, used by DOS) and my allocated large buffer.
I'm looking for a link to code samples or finished implementation of these features with XMS (unreal mode?) and using the DPMI API.
TL;DR The smallest achievable overhead overhead for writing 32-bit DOS programs is 5800 .. 9800 bytes.
I've looked around for DOS extenders, and here is what I've found:
- It's possible to build a solution upon the PMODE 3.07 source code, giving <7500 bytes of DOS extender overhead in the program, 5800 bytes if compressed), but it needs substantial amount of work becaue of manual setup and relocations. TASM source code is available.
- D3X dx3lite.exe can do it out-of-the-box with 8200 bytes compressed. TASM source code is available. Currently only FASM assembler specially modified for the Adam + relocations binary format can be used for development, but it should be possible to generate an object file (ELF, OMF or COFF) with NASM and convert it manually.
- WDOSX 0.97 with 9720 bytes compressed is a convenient option, because it doesn't need any headers, and it works without relocations.
- Others are incomplete or add at least 10000 bytes of overhead.
More details about each DOS extender I've considered and the overhead they add:
- Xi Development Systems 1997-08-15: 4303 bytes; doesn't support VCPI, doesn't do relocations, doesn't have file I/O
- SYSTEM 64 v1.210: 6392 bytes, the actual program is 16408 bytes longer because of NUL blocks; most DOS file I/O functions are missing
- PMODE 3.07: 7048 bytes, the actual program is 424 bytes longer because of NUL blocks in the DOS .exe header
- RAW32 r3: 7270 bytes, the actual program is 4186 bytes longer because of NUL blocks, the actual program makes DOSBox crash
- PMODE 2.05: 7937 bytes, the actual program is 5867 bytes longer because of of NUL blocks
- D3X d3xlite.exe 2022-06-13 by CandyMan: 8200 bytes compressed
- WDOSX 0.97: 9720 bytes compressed
- PMODE/W 1.22: 10286 bytes
- E.O.S 3.0.5 eoslite.obj: 10800 bytes when compressed with WWPACK, default is uncompressed
- D3XX d3x.exe 2022-08-01: 10908 bytes
- Pro32 version 17 and also the version distributed with Pass32 2.5 assembler: 11273 bytes, the created .exe program makes DOSBox crash
- D3X 0.90 2004-10-09: 11880, the actual program is 4800 bytes longer because of NUL blocks
- PMODE/W 1.33: 11783 bytes
- ZRDX: 12400 bytes
- E.O.S 3.0.5 weoslite.exe: 13078 bytes when compressed with WWPACK, default compressed
- DOS/4GW, DOS/32A, PMODE/W, PMODE/DJ etc. add even more than 14000 bytes.
- DOSX shipped with Symantec C++ 6.1 21549 bytes