A single .exe binary which runs DOOM on DOS 6, Windows 95 and Windows 10 (and probably everything in between).
Quickstart
Run DOOM.EXE
on your OS of choice, making sure that a suitable .WAD file is present. DOOM1.WAD
, in this repo, is the shareware demo.
Introduction
DOS and Windows .exe files both start with a common header (the DOS "MZ" header), which might suggest that you can run programs for one OS on the other one. However, this is complicated by a few facts: DOS support was dropped in Windows a long time ago (DOS binaries don't load on Windows 10, for example), and DOS programs use a completely different execution environment.
This repo builds a single .exe file with a "polyglot" MZ header which allows it to load one program (the original DOOM) when running inside DOS, and a different program (a custom static build of Chocolate DOOM) when running on Windows.
The DOS binary
The DOS binary, DOOMD.EXE
, is exactly the original DOOM for DOS, derived from the shareware version that was widely distributed. DOOMDUPX.EXE
is the same binary, but packed with UPX to make it smaller.
The Windows binary
The Windows binary, DOOMW.EXE
, is a custom build of Chocolate DOOM, a source port of DOOM which hews very closely to the original. Chocolate DOOM is based on libSDL 1.2; this custom build integrates it statically rather than linking to libSDL dynamically. This binary is stripped. DOOMWUPX.EXE
is the same binary, but packed with UPX to make it smaller.
Build instructions
apt install mingw-w64 build-essential
on an Ubuntu 18.04 machine.- Download and unpack the source code for Chocolate DOOM 2.2.1,
SDL
1.2.15,SDL_mixer
1.2.7, andSDL_net
1.2.8. cd SDL-1.2.15; ./configure --enable-shared --enable-static --disable-directx --host=i686-w64-mingw32; make; sudo make install
cd SDL_mixer-1.2.7; ./configure --enable-shared --enable-static --host=i686-w64-mingw32; make; sudo make install
sudo mv /usr/local/lib/libSDL_mixer.* /usr/local/cross-tools/i386-mingw32/lib/; sudo mv /usr/local/include/SDL/SDL_mixer.h /usr/local/cross-tools/i386-mingw32/include/SDL/
(I could probably also have just set prefix correctly)- Apply this patch to
SDL_net
to eliminate the dependency oniphlpapi.dll
:
diff -ur a/SDL_net-1.2.8/SDLnet.c SDL_net-1.2.8/SDLnet.c
--- a/SDL_net-1.2.8/SDLnet.c 2012-01-15 16:20:10.000000000 +0000
+++ b/SDL_net-1.2.8/SDLnet.c 2020-11-13 18:49:24.602850922 +0000
@@ -212,6 +212,7 @@
return 0;
}
+#if 0
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == ERROR_BUFFER_OVERFLOW) {
pAdapterInfo = (IP_ADAPTER_INFO *) SDL_realloc(pAdapterInfo, ulOutBufLen);
if (pAdapterInfo == NULL) {
@@ -219,6 +220,9 @@
}
dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
}
+#else
+ return 0;
+#endif
if (dwRetVal == NO_ERROR) {
for (pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) {
cd SDL_net-1.2.8; ./configure --enable-shared --enable-static --host=i686-w64-mingw32; make; sudo make install
sudo rm /usr/local/cross-tools/i386-mingw32/lib/*.dll.a
. This eliminates the dynamic libraries to force static linking of SDL.cd chocolate-doom-2.2.1; ./configure --host=i686-w64-mingw32 --build=i386-linux LIBS="-lgdi32 -lwinmm -lwsock32"; make
i686-w64-mingw32-strip src/chocolate-doom.exe
Voila, a statically built version of Chocolate DOOM which runs on everything from Windows 95 to Windows 10 (might need msvcrt.dll
on old versions of Windows 95).
The merged binary
smash.py
merges the two binaries together to produce the merged binary DOOM.EXE
. What it basically does is extend the size of the DOS header to make room for a PE header, appends the entire Windows binary to the DOS binary, then inserts the PE header into the slack space and rewrites the section offsets appropriately. On DOS, the next_offset
in the header is ignored: DOS/4GW uses the executable size in the second and third WORDs of the DOS header to find the next binary to load. On Windows, the entire DOS header is ignored except for the next_offset
, which points to the PE header and thus loads the Windows binary.
DOOMUPX.EXE
, similarly, is generated by merging together the two UPX'd binaries DOOMDUPX.EXE
and DOOMWUPX.EXE
. It's quite a bit smaller, but on the use of UPX (plus the unusual file structure) seems to cause a lot of virus scanners to flag it as suspicious. It's the original version that was posted to Twitter.
Acknowledgements
Thanks @angealbertini (angea) for this neat challenge!