============================================================ Using DEBUG to trace the INT instruction ============================================================ -Ian! D. Allen - idallen@idallen.ca - www.idallen.com # Output from a debug script (int_push.txt) showing how INT places # values on the stack and how it loads CS:IP from the interrupt vector # in low memory. These comments (prefixed by '#') were added to the # script output file by hand, to explain what is going on. # First, fill memory with 2000h zeroes, to make things easier to see. # For the same reason, fill some of the stack area with zeroes. # -f 0100 l 2000 00 -f ffe0 l 20 00 # Assemble a small program that triggers INT 4h. -a 0100 1426:0100 int 4h 1426:0102 # Now display some of low memory (segment zero!), showing the first # eight DOS interrupt vectors. Each interrupt vector holds a new CS and # IP and takes 2+2=4 bytes. For "INT 4" we calculate that the new IP # will be loaded from low address (4*4)=0010 (0000:0010) and the new CS # will be loaded from high address (4*4+2)=0012 (0000:0012). We dump # this memory to find that location 000:0010 contains 0465 (new IP) and # 0000:0012 contains 0070 (new CS): -d 0000:0000 l 20 0000:0000 9E 01 00 00 00 04 70 00-16 00 6B DE 65 04 70 00 ......p...k.e.p. 0000:0010 65 04 70 00 54 FF 00 F0-08 80 00 F0 6F EF 00 F0 e.p.T.......o... # Display our starting registers and the stack area before the INT. # Note that this INT is a 2-byte instruction (bit pattern CD04). -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1426 ES=1426 SS=1426 CS=1426 IP=0100 NV UP EI PL NZ NA PO NC 1426:0100 CD04 INT 04 -d ffe0 l 20 1426:FFE0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1426:FFF0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ # Trace the INT. Note how the CS, IP, SP, and stack memory all change. # The IP is incremented by 2 bytes (the length of "INT 4") from 0100 to 0102. # The first item PUSHed by the INT is 2 bytes of Flags: F202 # Next pushed is the old CS (1426) followed by the incremented IP (0102). # The IP is loaded with the value from memory at 0000:0010 (0465) # The CS is loaded with the value from memory at 0000:0012 (0070) # IP: 0100 -> 0102 ; increment by length of instruction "CD04" # SP: FFEE -> FFEC ; decrement to PUSH two bytes of flags # [SP] = "2 bytes of flags" so [1426:FFEC] = "flags F202" # SP: FFEC -> FFEA ; decrement to PUSH two bytes of CS # [SP] = 1426 (CS) so [1426:FFEA] = 1426 # SP: FFEA -> FFE8 ; decrement to PUSH two bytes of IP # [SP] = 0102 (IP) so [1426:FFE8] = 0102 # IP = [0000:0010] = 0465 # CS = [0000:0012] = 0070 # -t AX=0000 BX=0000 CX=0000 DX=0000 SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1426 ES=1426 SS=1426 CS=0070 IP=0465 NV UP DI PL NZ NA PO NC 0070:0465 CF IRET -d ffe0 l 20 1426:FFE0 00 00 00 00 00 00 00 00-02 01 26 14 02 F2 00 00 ..........&..... 1426:FFF0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ # We see six bytes pushed on the stack - the SP went from FFEE to FFE8. # We are now about to execute code at CS:IP = 0070:0465, inside the # interrupt service routine for "INT 4h". Looking at the first # instruction of this routine (above), we see it is an immediate "return # from interrupt" - IRET - this particular service routine does nothing! # When the service routine does a "return from interrupt", the CS:IP and # Flags will all be restored, and we will be back in segment 1426 at # address 0102. # # Let's do the trace of the IRET instruction. These registers change: # IP: 0465 -> 0466 ; increment by length of instruction "CF" # IP = [SP] so IP = [1426:FFE8] so IP = 0102 # SP: FFE8 -> FFEA ; increment after POP of two bytes of IP # CS = [SP] so CS = [1426:FFEA] so CS = 1426 # SP: FFEA -> FFEC ; increment after POP of two bytes of CS # "2 bytes of flags" = [SP] so "flags" = [1426:FFEC] so "flags" = F202 # SP: FFEC -> FFEE ; increment after POP of two bytes of "flags" # -t AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1426 ES=1426 SS=1426 CS=1426 IP=0102 NV UP EI PL NZ NA PO NC 1426:0102 0000 ADD [BX+SI],AL DS:0000=CD # Compare the above registers with the registers before we executed INT 04. # As expected, the IRET reloaded the IP, the CS, and the flags, in that order. # We are back in our original code segement, right after the INT instruction. # "Real" interrupt service routines do many things before returning. # All done! -q