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
124 lines
2.7 KiB
NASM
124 lines
2.7 KiB
NASM
; int3_handler.asm -- install our own INT 3 handler (AH=25h), then trigger it twice:
|
|
; once with the one-byte CC and once with the two-byte CD 03.
|
|
; Prints how far past the trapping instruction the pushed return IP points, and the
|
|
; state of IF (interrupt flag) inside the handler versus after IRET.
|
|
bits 16
|
|
org 0x100
|
|
; --- save the old vector with AH=35h, install ours with AH=25h ---
|
|
mov ax, 3503h
|
|
int 21h ; ES:BX = current INT 3 handler
|
|
mov [old_off], bx
|
|
mov [old_seg], es
|
|
mov ax, 2503h
|
|
mov dx, handler
|
|
int 21h ; DS:DX = new handler for vector 3
|
|
|
|
sti ; make sure IF=1 before we trap, so the handler's IF=0 is visible
|
|
mov word [target], trap_cc
|
|
mov dx, m_cc
|
|
call puts
|
|
trap_cc:
|
|
int3 ; CC
|
|
call report
|
|
|
|
mov word [target], trap_cd
|
|
mov dx, m_cd
|
|
call puts
|
|
trap_cd:
|
|
db 0CDh, 03h ; CD 03
|
|
call report
|
|
|
|
; --- restore the old vector and exit ---
|
|
push ds
|
|
mov dx, [old_off]
|
|
mov ds, [old_seg]
|
|
mov ax, 2503h
|
|
int 21h
|
|
pop ds
|
|
mov ax, 4C00h
|
|
int 21h
|
|
|
|
; ------------------------------------------------------------------
|
|
; The handler runs with IF=0 and TF=0 (the CPU cleared them when it took the interrupt).
|
|
handler:
|
|
push bp
|
|
mov bp, sp
|
|
push ax
|
|
; stack now: [bp+0]=saved BP, [bp+2]=return IP, [bp+4]=return CS, [bp+6]=FLAGS
|
|
mov ax, [bp+2]
|
|
mov [ret_ip], ax
|
|
mov ax, [bp+6]
|
|
mov [flags_pushed], ax
|
|
pushf
|
|
pop ax ; FLAGS as the handler itself sees them
|
|
mov [flags_inside], ax
|
|
pop ax
|
|
pop bp
|
|
iret
|
|
|
|
report:
|
|
mov dx, m_delta
|
|
call puts
|
|
mov ax, [ret_ip]
|
|
sub ax, [target] ; how many bytes past the trapping instruction?
|
|
call putdec
|
|
mov dx, m_ifpush
|
|
call puts
|
|
mov ax, [flags_pushed]
|
|
mov cl, 9
|
|
shr ax, cl
|
|
and al, 1
|
|
add al, '0'
|
|
mov dl, al
|
|
mov ah, 02h
|
|
int 21h
|
|
mov dx, m_ifin
|
|
call puts
|
|
mov ax, [flags_inside]
|
|
mov cl, 9
|
|
shr ax, cl
|
|
and al, 1
|
|
add al, '0'
|
|
mov dl, al
|
|
mov ah, 02h
|
|
int 21h
|
|
mov dx, m_tfin
|
|
call puts
|
|
mov ax, [flags_inside]
|
|
mov cl, 8
|
|
shr ax, cl
|
|
and al, 1
|
|
add al, '0'
|
|
mov dl, al
|
|
mov ah, 02h
|
|
int 21h
|
|
mov dx, m_ifafter
|
|
call puts
|
|
pushf
|
|
pop ax
|
|
mov cl, 9
|
|
shr ax, cl
|
|
and al, 1
|
|
add al, '0'
|
|
mov dl, al
|
|
mov ah, 02h
|
|
int 21h
|
|
jmp crlf
|
|
|
|
m_cc db 'CC (INT3): $'
|
|
m_cd db 'CD 03 (INT 3): $'
|
|
m_delta db 'return IP = trap address + $'
|
|
m_ifpush db ', IF pushed = $'
|
|
m_ifin db ', IF in handler = $'
|
|
m_tfin db ', TF in handler = $'
|
|
m_ifafter db ', IF after IRET = $'
|
|
|
|
old_off dw 0
|
|
old_seg dw 0
|
|
target dw 0
|
|
ret_ip dw 0
|
|
flags_pushed dw 0
|
|
flags_inside dw 0
|
|
|
|
%include "common.inc"
|