Incorrect calculation of enry point in DOS .EXE
Brought to you by:
konst
This is what I'm seeing: ╔═════════════ Old Exe Header ══════════════╗ ║Signature = 'MZ' ║ ║Part Last Page = 0 [ bytes ] ║ ║Page count = 256 [ pages ] ║ ║Relocations count = 0 ║ ║Header size = 2 [ paragraphs ] ║ ║Minimum memory = 0000H [ paragraphs ]║ ║Maximum memory = 0000H [ paragraphs ]║ ║SS : SP = 0FFE:FFFEH ║ ║Check summ = 0 ║ ║CS : IP = FFFE:0020H ║ ║Table offset = 001CH [ bytes ] ║ ║Overlay Number = 0 ║ ║>Entry Point = 00100020H ║ ║Module Length = 130528 [ bytes ] ║ ║Image offset = 00000020H ║ ║New EXE header shift = 8B00001EH ║ ╚═══════════════════════════════════════════╝ The .EXE is only 131072 bytes in length and is perfectly functional, but the viewer says the entry point is beyond 1MB point in the file, which just can't be true. It's clear that the entry point's location in the file is obtained using the formula: 2(=header size in paras)*0x10 + 0xfffe(=CS)*0x10 + 0x20(=IP) = 0x100020 However, a combination of a real-mode segment selector and a 16 bit offset can never give you a physical memory address greater than 0xFFFFF (because the max selector of 0xFFFF times 0x10 plus the max offset of 0xFFFF gives you 0xFFFFF). The formula lacks a mask/truncation and should be something like this instead: 2(=header size in paras)*0x10 + ((0xfffe(=CS)*0x10 + 0x20(=IP)) & 0xFFFFF) = 0x20. And that's the case, the first instruction to execute is at offset 0x20 in the file, right after the .EXE header. The same problem may exist with the SS:SP pair, if SS:SP is used for locating the stack within the file.
Actually, 0xFFFF*0x10 + 0xFFFF = 0x10FFEF (and not 0xFFFFF), but such an address would only be accessible if A20 is enabled, otherwise it would be truncated to 0xFFEF.
Nonetheless, really large 16-bit .EXEs in DOS would need to begin at low physical addresses and they wouldn't be able to cross the region where the BIOS and video buffer are (e.g. above 0xA0000). So, the 0xFFFFF mask is still needed in the formula.