A few weeks ago I had the questionable pleasure of diving into the math exception handler of WIN87EM.DLL, the Windows 3.1 math emulator and FPU support library. Actually WIN87EM.DLL appears to have been first shipped with Windows 3.0, and the version in Windows 3.1 is more or less identical. The version shipped with Windows 3.11 is byte for byte identical to the one in Windows 3.1.
The main function of WIN87EM.DLL is, as the name suggests, an x87 floating-point emulator. It appears to be an outgrowth of the math emulation packages shipped with many Microsoft languages. But even on a system with x87 hardware, WIN87EM.DLL has some work to do.
Namely WIN87EM.DLL intercepts math errors (exceptions). Depending on the system type, WIN87EM.DLL hooks either NMI vector 2 (PC and PC/XT) or IRQ 13 (PC/AT and compatibles).
The math interrupt handler in WIN87EM.DLL is very, very strange. It bears all the hallmarks of code that was written, rewritten, rewritten again, hacked, tweaked, modified, and eventually beaten into submission even if the author(s) had no real idea why it finally worked.
Now, x87 math error handing is a very tricky subject where numerous details changed over FPU and CPU generations, and Intel had a fair share of bugs in this area. But the code in WIN87EM.DLL looks very much like the result of changes made in desperation until it worked somehow, even though the changes made little or no sense.
The IRQ 13 handler in WIN87EM.DLL performs the following steps:
The not so crazy looking code executes FNSTENV to store the FPU environment, swaps in the previously saved status word (which was subsequently changed by FNCLEX), examines the code at the stored FPU error pointer to see if instruction prefixes should be skipped (that is where things may crash), enables interrupts with STI, and finally jumps to common code that’s executed on both PCs and ATs and handles the actual math error.
All in all, the math error interrupt handler in WIN87EM.DLL makes very little sense. I am extremely doubtful that, for example, writing to I/O port F0h four times does anything useful, or that executing FNCLEX twice is better than doing it once. However, it is entirely possible that the extra time it takes might do something. Likewise the slowdown loops that push and pop AX are very unlikely to be necessary, but may have done something seemingly useful on some particular system.
The code really does look like a desperate attempt to make things work, and there is some possibility that it is the result of trying to support broken hardware. Other similar error handlers I looked at don’t appear nearly as convoluted and are much more “by the book”.
We’ll probably never know why the code ended up so crazy, but we can speculate.