Add interrupts module: INT 3 (CC breakpoint) vs INT 21h (DOS services)

NASM sources, DOSBox/FreeDOS Debug/Unicorn harness, captured output and 31
assertions backing the ankurm.com article "INT 3 vs INT 21h in 8086 Assembly".

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KqJyCidz3ZgRyHABv2GVJh
This commit is contained in:
2026-09-30 19:10:56 +00:00
co-authored by Claude Sonnet 5.5
commit 09af523f8c
27 changed files with 1029 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
1 ; opcodes.asm -- which bytes does each spelling assemble to? (read the listing, never run)
2 bits 16
3 org 0x100
4 00000000 CC int3 ; the one-byte breakpoint -> CC
5 00000001 CD03 int 3 ; "INT n" with n = 3 in NASM -> CD 03
6 00000003 CD03 db 0CDh, 03h ; the same two bytes, written out -> CD 03
7 00000005 CD21 int 21h ; DOS entry point -> CD 21
8 00000007 CD10 int 10h ; BIOS video -> CD 10
9 00000009 CE into ; one-byte INTO -> CE
+2
View File
@@ -0,0 +1,2 @@
Hello from INT 21h, AH=09h
ERRORLEVEL is at least 7
+15
View File
@@ -0,0 +1,15 @@
AH=30h DOS version : 5.0
AH=2Ah/2Ch date+time ranges : ok ok
AH=02h + AH=06h : AB
AH=01h + AH=0Ah (stdin) : echo -> Ankur
AH=01h got 0x5A ; AH=0Ah count = 5, text = Ankur
AH=25h/35h vector 60h : ok
AH=48h/49h alloc+free 4 KB : ok
AH=48h ask for 1 MB (fails) : CF=1 AX=0008 ; largest block (paragraphs) = 8E6C
AH=3Ch/40h/3Dh/3Fh/42h : 12 bytes read ; LSEEK(end) says size = 12
AH=56h + AH=4Eh findfirst : U.TXT size = 12
AH=41h delete, reopen fails : CF=1 AX=0002
AH=39h/3Ah mkdir+rmdir : ok ; AH=19h drive = 2
AH=4Bh exec child : Hello from INT 21h, AH=09h
AH=4Dh return code = 7 type = 0
+2
View File
@@ -0,0 +1,2 @@
CC (INT3): return IP = trap address + 1, IF pushed = 1, IF in handler = 0, TF in handler = 0, IF after IRET = 1
CD 03 (INT 3): return IP = trap address + 2, IF pushed = 1, IF in handler = 0, TF in handler = 0, IF after IRET = 1
+2
View File
@@ -0,0 +1,2 @@
before INT3
after INT3 (program survived)
+26
View File
@@ -0,0 +1,26 @@
-u 100 L9
072E:0100 B81111 MOV AX,1111
072E:0103 CC INT 3
072E:0104 B82222 MOV AX,2222
072E:0107 B8004C MOV AX,4C00
-g
Unexpected breakpoint interrupt
AX=1111 BX=0000 CX=000C DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=072E ES=072E SS=072E CS=072E IP=0104 NV UP EI PL ZR NA PE NC
072E:0104 B82222 MOV AX,2222
-r
AX=1111 BX=0000 CX=000C DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=072E ES=072E SS=072E CS=072E IP=0104 NV UP EI PL ZR NA PE NC
072E:0104 B82222 MOV AX,2222
-t
AX=2222 BX=0000 CX=000C DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=072E ES=072E SS=072E CS=072E IP=0107 NV UP EI PL ZR NA PE NC
072E:0107 B8004C MOV AX,4C00
-r
AX=2222 BX=0000 CX=000C DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=072E ES=072E SS=072E CS=072E IP=0107 NV UP EI PL ZR NA PE NC
072E:0107 B8004C MOV AX,4C00
-g
Program terminated normally (0000)
-q
+25
View File
@@ -0,0 +1,25 @@
-u 100 L9
072E:0100 B81111 MOV AX,1111
072E:0103 CD03 INT 03
072E:0105 B82222 MOV AX,2222
072E:0108 B8004C MOV AX,4C00
-g
AX=1111 BX=0000 CX=000D DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=072E ES=072E SS=072E CS=072E IP=0104 NV UP EI PL ZR NA PE NC
072E:0104 03B82222 ADD DI,[BX+SI+2222] DS:2222=0000
-r
AX=1111 BX=0000 CX=000D DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=072E ES=072E SS=072E CS=072E IP=0104 NV UP EI PL ZR NA PE NC
072E:0104 03B82222 ADD DI,[BX+SI+2222] DS:2222=0000
-t
AX=1111 BX=0000 CX=000D DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=072E ES=072E SS=072E CS=072E IP=0108 NV UP EI PL ZR NA PE NC
072E:0108 B8004C MOV AX,4C00
-r
AX=1111 BX=0000 CX=000D DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=072E ES=072E SS=072E CS=072E IP=0108 NV UP EI PL ZR NA PE NC
072E:0108 B8004C MOV AX,4C00
-g
Program terminated normally (0000)
-q
+9
View File
@@ -0,0 +1,9 @@
clean run, no breakpoint:
CX=3
CC patch=CC trap: vector=3 return IP=7C03 (site=7C02, +1) debugger restores IP=7C02
after resume: CX=3 (expected 3), final IP=7C05
CD 03 patch=CD03 trap: vector=3 return IP=7C04 (site=7C02, +2) debugger restores IP=7C03
after resume: CX=0 (expected 3), final IP=7C64
RESULT: PASS
+8
View File
@@ -0,0 +1,8 @@
Title: DEBUG
Version: 2.50
Entered-date: 2024-06-01
Copying-policy: MIT License
nasm: NASM version 2.16.01
dosbox: DOSBox version 0.74-3
unicorn: 2.1.4
python: Python 3.11.15
+31
View File
@@ -0,0 +1,31 @@
PASS int3 assembles to the single byte CC
PASS NASM 'int 3' assembles to CD 03
PASS int 21h assembles to CD 21
PASS into assembles to CE
PASS hello21 prints its string
PASS AH=4Ch return code 7 visible as ERRORLEVEL
PASS AH=30h reports a version
PASS AH=2Ah/2Ch ranges ok
PASS AH=02h+06h write AB
PASS AH=01h returned 5A ('Z') and AH=0Ah counted 5 chars 'Ankur'
PASS AH=25h/35h round trip
PASS AH=48h/49h alloc+free ok
PASS AH=48h 1 MB request fails CF=1 AX=0008
PASS file I/O: 12 bytes read, LSEEK says 12
PASS findfirst sees U.TXT size 12
PASS reopening deleted file: CF=1 AX=0002
PASS mkdir/rmdir ok
PASS child exit code 7, termination type 0 via AH=4Dh
PASS CC: return IP = trap + 1
PASS CD 03: return IP = trap + 2
PASS IF and TF are 0 inside the handler, IF back to 1 after IRET
PASS IF pushed on the stack was 1
PASS INT 3 with no handler: program survives under DOSBox
PASS DEBUG + CC: 'Unexpected breakpoint interrupt' and IP=0104
PASS DEBUG + CC: next instruction after trap is MOV AX,2222
PASS DEBUG + CC: single-step then AX=2222
PASS DEBUG + CD 03: no breakpoint message
PASS DEBUG + CD 03: stops at IP=0104 inside the INT 03 instruction
PASS DEBUG + CD 03: MOV AX,2222 never runs (AX stays 1111 after stepping)
PASS Unicorn: CC patch trap return IP = site+1, resume gives CX=3
PASS Unicorn: CD 03 patch trap return IP = site+2 and resume goes wrong