Reply 20 of 24, by Myloch
- Rank
- Oldbie
English Pc globe 4.0 suffers this too.
"Gamer & collector for passion, I firmly believe in the preservation and the diffusion of old/rare software, against all personal egoisms"
English Pc globe 4.0 suffers this too.
"Gamer & collector for passion, I firmly believe in the preservation and the diffusion of old/rare software, against all personal egoisms"
I've made a little progress on tracking down why Stargunner has this problem.
Those values I posted before are realmode register dumps.
Interrupt divide by zero, stack:2DB5 C000 3A07 000C 0000 0000 2CCB 00000000 28E2 0000 0000 12A2
It felt like chasing ghosts! The PMODE/W stub doesn't have a string like "Interrupt divide by zero, stack:", and Watcom (which it was compiled with) doesn't do that either, and the game's Linear Executable (which is not compressed btw!) also doesn't have this string. So where is this coming from? Not software, apparently.
Upon staring this code down with DEBUG from FreeDOS, I got a little better output, and in fact one layer deeper into the offending code:
Divide errorAX=0000 BX=00F0 CX=0150 DX=0100 SP=03E8 BP=0000 SI=000C DI=0000DS=0000 ES=136D SS=227F CS=C000 IP=2DB5OV UP EI PL NZ NA PE CYC000:2DB5 F7F3 div bx
Segment 0xC000 is the VGA BIOS. So a quick glance at my VGA BIOS courtesy of IDA Free 9.2 and https://www.3dfxzone.it/dir/3dfx/utilities/?objid=558, we get the offending code:
seg000:2D8F ; =============== S U B R O U T I N E =======================================seg000:2D8Fseg000:2D8Fseg000:2D8F sub_2D8F proc near ; CODE XREF: sub_2C9D:loc_2CC8↑pseg000:2D8F ; sub_2C9D:loc_2CF9↑pseg000:2D8F push bxseg000:2D90 push dxseg000:2D91 push siseg000:2D92 call sub_2DE8seg000:2D95 mov al, ds:byte_449seg000:2D98 call sub_2DFEseg000:2D9B mov bx, axseg000:2D9D mov al, ds:byte_449seg000:2DA0 call sub_2BABseg000:2DA3 jmp cs:off_2DD6[si]seg000:2DA8 ; ---------------------------------------------------------------------------seg000:2DA8seg000:2DA8 loc_2DA8: ; CODE XREF: sub_2D8F+14↑jseg000:2DA8 ; DATA XREF: seg000:off_2DD6↓o ...seg000:2DA8 div bxseg000:2DAA imul ds:word_485seg000:2DAE and al, 0F0hseg000:2DB0 jmp short loc_2DCFseg000:2DB2 ; ---------------------------------------------------------------------------seg000:2DB2seg000:2DB2 loc_2DB2: ; CODE XREF: sub_2D8F+14↑jseg000:2DB2 ; DATA XREF: seg000:2DDC↓o ...seg000:2DB2 shl bx, 2seg000:2DB5seg000:2DB5 loc_2DB5: ; CODE XREF: sub_2D8F+14↑jseg000:2DB5 ; DATA XREF: seg000:2DDA↓o ...seg000:2DB5 div bxseg000:2DB7 and al, 0F0hseg000:2DB9 jmp short loc_2DCFseg000:2DBB ; ---------------------------------------------------------------------------seg000:2DBBseg000:2DBB loc_2DBB: ; CODE XREF: sub_2D8F+14↑jseg000:2DBB ; DATA XREF: seg000:2DE6↓oseg000:2DBB div bxseg000:2DBD mov bx, 3seg000:2DC0 cwdseg000:2DC1 div bxseg000:2DC3 imul ax, 3seg000:2DC6seg000:2DC6 loc_2DC6: ; CODE XREF: sub_2D8F+3E↓jseg000:2DC6 test al, 7seg000:2DC8 jz short loc_2DCFseg000:2DCA sub ax, 3seg000:2DCD jmp short loc_2DC6seg000:2DCF ; ---------------------------------------------------------------------------seg000:2DCFseg000:2DCF loc_2DCF: ; CODE XREF: sub_2D8F+21↑jseg000:2DCF ; sub_2D8F+2A↑j ...seg000:2DCF call nullsub_4seg000:2DD2 pop siseg000:2DD3 pop dxseg000:2DD4 pop bxseg000:2DD5 retnseg000:2DD5 sub_2D8F endp
Now what's interesting is that how the `div` works in realmode. Remember, these are our register values, I'll only put the ones that matter:
AX=0000 BX=00F0 DX=0100
`div` will divide a 32 bit integer made of DX and AX by the specified source register, in this case BX, and store the quotient in AX, and the remainder in DX. So we got this on our hands:
0x01000000 / 0x00F0
Or in other words
16,777,216 / 240
The result of this division as per the implementation of `div`, will make `0x11111` go to AX, and `0x10` go to DX. But, this is incredibly wrong because it overflows the register. So the real error is not necessarily a divide by zero, but an overflow as a result of division. So we're probably looking for `int 10h` calls that mess things up.
Going back to Stargunner, with this renewed intel we can correctly interpret the cryptic dump:
Interrupt divide by zero, stack:AX=2DB5 BX=C000 CX=3A07 DX=000C SP=0000 BP=0000 SI=2CCB DI=0000DS=0000 ES=28E2 SS=0000 CS=0000 IP=12A2
However, I did not find anything interesting in CS:IP 0x000012A2.
I'll post more, when I find it.
Audigy 2 ZS in FreeDOS
LinLin adapter documentation
+ various capacitor list threads
How did you get that visual debugger for a DOS executable?
Kahenraz wrote on 2025-11-25, 02:10:How did you get that visual debugger for a DOS executable?
The screenshot you see is a disassembly of Voodoo 5500 VBIOS 1.06 that I linked, in IDA 9.2 Free for Linux.
To get a visual disassembly of a DOS executable, it depends what executable we're talking about. Stargunner 1.0b has 2 executables that exhibit exactly the same problem:
1. SETUP.EXE, 171613 bytes, sha256 b3137db05eae51cdfd3c16c19b2c5dc07c56eefebb7b4f0bb5004057176c69dc
2. STARGUN.EXE, 1066351 bytes, sha256 e0a61da0fd6c73f3305c3c02f1c7b27d1ea5f637f155a1373a1f2965564ef551
Both executables use the same PMODE/W v1.21 stub. You can replace the v1.21 stub with v1.33 stub, or replace it with a DOS32A 9.1.2 stub. All 3 stubs will run into the same problem while there are games that work fine with DOS32A on speedy CPUs, which indicates the problem is not caused by the stub.
In order to progress towards getting a visual disassembly on either of those files, you must strip the stub in order to obtain a Linear Executable. In both cases, the stub is 9808 bytes long, but the stripping process (done with PMWBIND.EXE or SB.EXE) will change 2 bytes early on in the Linear Executable.
Once you have obtained the Linear Executable, you have to analyze it with IDA 4.1, which has a free version available online: https://sourceforge.net/projects/hawk800/file … 41.zip/download
But IDA 4.1 is a TUI program, you probably say. Yes. But the database you can generate with IDA 4.1 is still readable with IDA 5.0, the first IDA to feature a GUI. Once the analysis is complete, save the database and open it with IDA 5.0.
If you skip IDA 4.1 and instead analyze the Linear Executable with IDA 5.0, you won't get the correct analysis. For comparison:
- IDA 5.0 LE analysis of STARGUN.EXE will yield 42 functions, because IDA 5.0 and onwards do not support Linear Executables at all
- IDA 4.1 LE analysis of STARGUN.EXE will yield 2492 functions
Audigy 2 ZS in FreeDOS
LinLin adapter documentation
+ various capacitor list threads
FWIW, the R6003 error is produced by Microsoft’s C runtime library.