The World’s Smallest (Useful!) Program :)
Thought I’d share a funny little program with you from back in 1986. Here it is: to my knowledge the world’s smallest (useful) IBM PC computer program:
PUSHÂ AX POPÂ Â DS XORÂ Â BYTE PTR [16], 7 RETF
That computer program in x86 assembler is exactly 9 bytes long and actually does do something useful— it toggles the print screen function (if it’s on, it turns it off and vice versa). It works based on some analysis of the IBM PC ROM BIOS listing – at memory location F000:FF53
there is an IRET
instruction (return from interrupt). At F000:FF54
there is the beginning of the PRTSC interrupt handler. So, think about that – we have FF53
and FF54
; the last nibble of the octet is either 3 or 4. Furthermore, the interrupt table at the top of memory (0000:0000
) contains at position 5 (hex positions 0014
to 0017
) the address of the PRTSC interrupt handler (00 F0 54 FF
in little-endian notation). So to toggle print screen…if we could just change that “54†to be “53†(the address of the IRET
function of the preceding interrupt vector) we’d have it done.
The code above works by using lots of tricks: the AX
“accumulator” register is always zero when a DOS command file (.COM extension) runs, and the DS
data segment register is what you use to manipulate memory. So, to zero out the DS
register (to access the top of memory where the PRTSC interrupt is) we push AX
onto the stack and pop DS
off. This is equivalent to assigning AX to DS directly—but (even though it is two instructions) it is smaller (one byte each for the PUSH
/ POP
vs. three bytes for the equivalent MOV DS, AX
). This was a revelation to me—at a very basic level sometimes you really do choose size (the two instructions, that require four cycles) vs. speed (the single MOV
command that uses three cycles but takes up three bytes on disk).
Then we use the XOR
command to modify the data byte at offset 0x16 (that’s hexadecimal; 22 decimal). We XOR whatever was in the data byte with a 7. Let’s look at what happens:
3Â Â Â Â Â 0011 XORÂ 7Â Â Â Â Â 0111 --Â Â Â Â Â ---- 4Â Â Â Â Â 0100
And, going the other way…
4Â Â Â Â Â 0100 XORÂ 7Â Â Â Â Â 0111 --Â Â Â Â Â ---- 3Â Â Â Â Â 0011
By XOR’ing with a 7, we are essentially switching the values between 3 and 4.
Finally, the program uses a little trick of MS-DOS. (Remember, MS-DOS was initially written for CP/M compatibility, just do a search for INT 21 FUNC 09 for a view of how CP/M allowed strings to be printed to the screen.) For badly-written programs (which ties back to Norwhich University’s Dr. Mich Kabay’s comments on the great unwashed horde in the 80s writing any old garbage and putting it onto a machine), it wasn’t unusual for programs in CP/M simply to have a RETF
(far return) without being wrapped in a CALL
statement. Effectively, CP/M translated this as “return me to the operating system NOW” which effectively terminates the running program. Bill Gates (really, Tim Paterson) put in the same provision for DOS so that instead of me writing the accepted INT 20
(IBM PC ROM BIOS standard end program, took two bytes) or even more standards-based MOV AH, 4E; INT 21
(the best-practices way to end a program; but at a cost of 4 bytes; my gosh, did they think we all had 10MB hard disks??) all I had to do was a simple one-byte RETF
and my program would end. I got to save at least a byte of space!
Here’s top of memory prior to doing the run:
0000:0010Â XX XX XX XX 00 F0 54 FF [ ... other interrupt vectors ... ]
After running it once:
0000:0010Â XX XX XX XX 00 F0 53 FF [ ... other interrupt vectors ... ]
And after running it again:
0000:0010Â XX XX XX XX 00 F0 54 FF [ ... other interrupt vectors ... ]
Very amusing; to quote Homer Simpson: “Print screen goes off, print screen goes on. Print screen goes off, print screen goes on.” And all in 8 bytes (not counting the RETF
).
If the machine wasn’t strictly compatible with IBM PC ROM BIOS then my little gem wouldn’t work and would in fact have a real possibility of crashing the system. Well, you can’t make an omelet without breaking a few eggs!
Leave a Reply