Rod Pemberton
; STDERROR.ASM
BITS 16
ORG 0x100 ; require for .COM file
SECTION .text
start: jmp short start1
nop
old_vector: dw 00h,00h ; save old DOS int 21 vector
start1:
mov ax, 0
mov es, ax
les bx, [es:21h * 4] ; read the vector for DOS int 21
mov [old_vector], bx ; save it so we can chain to it
mov [old_vector + 2], es
mov ax, 0
mov es, ax
cli ; disable interrupts while we write
mov word [es:21h * 4], isr ; chain our handler to DOS int 21
mov [es:(21h * 4) + 2], cs
sti ; enable interrupts
mov ax, 3100h ; function code to become resident
mov dx, last / 16 + 11h ; reserve memory paragraphs for us
int 21h ; return to DOS but remain resident
; This interrupt service routine is chained to the main DOS int 21 vector.
isr: cmp ah, 40h ; function code = write to file?
jne exit ; jump if no, don't do anything
cmp bx, byte 2 ; handle = stderr?
jne exit ; jump if no, don't do anything
dec bx ; force handle to stdout
exit: jmp far [cs:old_vector] ; let DOS do its thing
last equ $ - start ; how much memory we use
I'm not sure if the main aim was binary or functional compatibility,
but locating the initialisation/setup code at the end will result in a
smaller memory footprint of the resident code. I.e.
start: jmp short start1
nop ;;-------> I guess this is for compat??
old_vector: dw 00h,00h ; save old DOS int 21 vector
; This interrupt service routine is chained to the main DOS int 21 vector.
isr: cmp ah, 40h ; function code = write to file?
jne exit ; jump if no, don't do anything
cmp bx, byte 2 ; handle = stderr?
jne exit ; jump if no, don't do anything
dec bx ; force handle to stdout
exit: jmp far [cs:old_vector] ; let DOS do its thing
last equ $ - start ; how much memory we use
; ----> we don't need to keep this code resident
start1:
mov ax, 0
mov es, ax
les bx, [es:21h * 4] ; read the vector for DOS int 21
mov [old_vector], bx ; save it so we can chain to it
mov [old_vector + 2], es
mov ax, 0
mov es, ax
cli ; disable interrupts while we write
mov word [es:21h * 4], isr ; chain our handler to DOS int 21
mov [es:(21h * 4) + 2], cs
sti ; enable interrupts
mov ax, 3100h ; function code to become resident
mov dx, last / 16 + 11h ; reserve memory paragraphs for us
int 21h ; return to DOS but remain resident
As a final comment, the ISR itself could be made even smaller :)
; This interrupt service routine is chained to the main DOS int 21 vector.
isr: cmp ah, 40h ; function code = write to file?
jne exit ; jump if no, don't do anything
cmp bx, byte 2 ; handle = stderr?
jne exit ; jump if no, don't do anything
dec bx ; force handle to stdout
exit: db 0xEA ; "jmp far immediate" opcode
old_vector: dw 00h,00h ; save old DOS int 21 vector
Pete
--
"We have not inherited the earth from our ancestors,
we have borrowed it from our descendants."