While researching the history of Microsoft’s segmented-executable linker originally called LINK4.EXE, I came across an OS/2 executable that was publicly released almost a year before the first OS/2 SDK was shipped, and many months before OS/2 was even announced. In fact the executable was likely released before the name “OS/2” even existed.
The file is EXEHDR.EXE, dated June 11, 1986 (size 32,896 bytes). It was shipped in the Microsoft Windows 1.03 SDK and then again unchanged in the Windows 1.04 SDK. For reference, OS/2 was announced on April 2, 1987 and the first OS/2 SDK was shipped around May 1987.
The mid-1986 EXEHDR.EXE is a classic dual-mode executable, with a DOS-compatible “stub” followed by an OS/2 NE format module—essentially two separate executables in a single file (it is not a bound executable). The OS/2 portion imports several routines from the DOSCALLS module, such as DOSOPEN, DOSREAD, DOSALLOCSEG, DOSGETVERSION, or DOSEXIT. It is notable that this old EXEHDR.EXE imports from DOSCALLS by name, while actual OS/2 applications imported by ordinal number.
This EXEHDR.EXE from June 1986 is currently the earliest known OS/2 executable released outside Microsoft/IBM. There is a slight chance that others might have been published with earlier Windows SDKs or perhaps some other Microsoft tools. It is likely that the release of this dual-mode EXEHDR.EXE was an omission, as the OS/2 portion effectively wasted about 16KB of disk space.
The June 1986 EXEHDR utility does not run on any known version of OS/2 (either early betas from mid-1987 or later 32-bit versions). On the other hand, the utility—unsurprisingly—understands its own format and produces the following output when run against itself in a DOS environment:
Magic number: 5a4dH Bytes on last page: 128 Pages in file: 65 Relocations: 3 Paragraphs in header: 32 Extra paragraphs needed: 0 Extra paragraphs wanted: 65535 Initial stack location: 0455:0800 Word checksum: ca7fH Entry point: 0000:1206 Relocation table address: 0040H Reserved words: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 New .EXE header address: 4400H Memory needed: 32K Module: EXEHDR Description: EXEHDR.EXE Linker version: 5.00 32-bit Checksum: f7de06d1 Data: INSTANCE Segment Table: 00004440 length 16 Resource table: 00004450 length 0 Resident Names Table: 00004450 length 10 Imported Names Table: 0000445c length 157 Entry Table: 000044f9 length 10 Non-resident Names Table: 00004503 length 14 Movable entry points: 1 Segment sector size: 512 Entry point: seg 1 offset 0fd7 Stack: seg 2 offset 16d0 DGROUP: 2 no. type address file mem flags 1 CODE 00004600 02ee1 02ee1 relocs, movable, preload 2 DATA 00007600 00a80 016d0 movable, preload ord seg offset name 1 type offset target PTR 2ca2 imp DOSCALLS.DOSWRITE PTR 1cad imp DOSCALLS.DOSSETVEC PTR 1729 imp DOSCALLS.DOSEXIT PTR 0ff5 imp DOSCALLS.DOSGETVERSION PTR 2a5c imp DOSCALLS.DOSALLOCSEG PTR 2dba imp DOSCALLS.DOSREALLOCSEG PTR 2c8e imp DOSCALLS.DOSCHGFILEPTR PTR 2d4a imp DOSCALLS.DOSCLOSE PTR 2e1a imp DOSCALLS.DOSOPEN PTR 2e38 imp DOSCALLS.DOSQFILEMODE PTR 1c87 imp DOSCALLS.DOSQHANDTYPE PTR 2c73 imp DOSCALLS.DOSREAD PTR 2d96 imp DOSCALLS.DOSSETFILEMODE BASE 1b6f seg 2 offset 0000
Both the DOS and OS/2 executables included in EXEHDR.EXE had been built with Microsoft C, presumably version 4.0 with unreleased OS/2 run-time libraries.
It is currently not known whether anyone discovered this back in 1986, or if they understood the implications. The fact that Microsoft was working on “Advanced DOS” was understood at the time, although not many details were known.
Worth noting is also the fact that the LINK4.EXE segmented-executable linker (dated July 18, 1986) shipped with the Windows 1.03 SDK also clearly included some OS/2 support. The list of keywords includes for example PROTMODE and IOPL, neither of which was used with Windows 1.x/2.x or with the multitasking DOS 4.
How did you determine that this version of exehdr.exe was designed for a proto-OS/2 not Windows, MT-DOS 4, or one of the fabled but never shipped attempts at porting DOS itself to protected mode or some other product started and canceled before the OS/2 agreement was finalized? The NE structure got used a lot. Someone at MS liked the basic design of overlapping structures appended to a previous structure; a bunch of API and file formats used the system.
it is like all the parts were there in 1986 for something chicago-ish before we eventually got there in 1995. CP-DOS must have been able to actually run things, and I’m guessing via the tripple fault on the 286 there was at least some DOS compatibility. Windows 2.0 was still a year away, but in that time MS would already have pushed out Windows/386 the DOS hypervisor.
And even assuming MS could pull it all together before 1990, would there be room in MS’s world for MS-DOS+Windows and CP-DOS/Windows? I guess Windows 3.0 wouldn’t have needed to happen. But then again MS was still far too timid to sell EuroDOS 4.0 on its own, just as CP-DOS was at some runnable state, but again wasn’t for larger sale.
Now that I’ve seen actual multitasking DOS 4, it’s clear that its API is entirely different from OS/2, because it is primarily DOS INT 21h based. On the other hand, the EXEHDR executable in question (the NE part of it) does not use INT 21h at all but rather only imports from DOSCALLS (the imports are OS/2 API functions, see listing). Note that multitasking DOS 4 also had a DOSCALLS module, but exported a completely different set of functions.
On the other hand, looking at what this EXEHDR understands, there’s the “protected mode only” flag which would not apply to either DOS or Windows 1.x/2.x.
You mean Microsoft was too timid to sell multitasking DOS 4.0 in retail? Because they did try selling it to OEMs and the OEMs overwhelmingly said “no thanks”.
What you might also find interesting is that this EXEHDR can recognize executables which use 386 instructions and contain 32-bit segments with 32-bit offsets and 48-bit far pointers. Clearly Microsoft was working on the technology but the world had to wait a while. This is no doubt related to the fact that Microsoft at that time had a 32-bit XENIX compiler and was developing a 386 port of XENIX.