The Art of
ASSEMBLY LANGUAGE PROGRAMMING

Chapter Eighteen (Part 1)

Table of Content

Chapter Eighteen (Part 3)

CHAPTER EIGHTEEN:
RESIDENT PROGRAMS (Part 2)
18.2 - Active vs. Passive TSRs
18.2 Active vs. Passive TSRs

Microsoft identifies two types of TSR routines: active and passive. A passive TSR is one that activates in response to an explicit call from an executing application program. An active TSR is one that responds to a hardware interrupt or one that a hardware interrupt calls.

TSRs are almost always interrupt service routines. Active TSRs are typically hardware interrupt service routines and passive TSRs are generally trap handlers. Although in theory it is possible for a TSR to determine the address of a routine in a passive TSR and call that routine directly the 80x86 trap mechanism is the perfect device for calling such routines so most TSRs use it.

Passive TSRs generally provide a callable library of routines or extend some DOS or BIOS call. For example you might want to reroute all characters an application sends to the printer to a file. By patching into the int 17h vector you can intercept all characters destined for the printer. Or you could add additional functionality to a BIOS routine by chaining into its interrupt vector. For example you could add new function calls to the int 10h BIOS video services routine by looking for a special value in ah and passing all other int 10h calls on through to the original handler. Another use of a passive TSR is to provide a brand new set of services through a new interrupt vector that the BIOS does not already provide. The mouse services provided by the mouse.com driver is a good example of such a TSR.

Active TSRs generally serve one of two functions. They either service a hardware interrupt directly or they piggyback off the hardware interrupt so they can activate themselves on a periodic basis without an explicit call from an application. Pop-up programs are a good example of active TSRs. A pop-up program chains itself into the PC's keyboard interrupt (int 9). Pressing a key activates such a program. The program can read the PC's keyboard port to see if the user is pressing a special key sequence. Should this keysequence appear the application can save a portion of the screen memory and "pop-up" on the screen perform some user-requested function and then restore the screen when done. Borland's Sidekick' program is an example of an extremely popular TSR program though many others exist.

Not all active TSRs are pop-ups though. Certain viruses are good examples of active TSRs. They patch into various interrupt vectors that activate them automatically so they can go about their dastardly deeds. Fortunately some anti-viral programs are also good examples of active TSRs they patch into those same interrupt vectors and detect the activities of a virus and attempt to limit the damage the virus may cause.

Note that a TSR may contain both active and passive components. That is there may be certain routines that a hardware interrupt invokes and others that an application calls explicitly. However if any routine in a resident program is active we'll claim that the entire TSR is active.

The following program is a short example of a TSR that provides both active and passive routines. This program patches into the int 9 (keyboard interrupt) and int 16h (keyboard trap) interrupt vectors. Every time the system generates a keyboard interrupt the active routine (int 9) increments a counter. Since the keyboard usually generates two keyboard interrupts per keystroke dividing this value by two produces the approximate number of keys typed since starting the TSR. A passive routine tied into the int 16h vector returns the number of keystrokes to the calling program. The following code provides two programs the TSR and a short application to display the number of keystrokes since the TSR started running.

; This is an example of an active TSR that counts keyboard interrupts
; once activated.
; The resident segment definitions must come before everything else.
ResidentSeg     segment para public 'Resident'
ResidentSeg     ends
EndResident     segment para public 'EndRes'
EndResident     ends
                .xlist
include         stdlib.a
includelib      stdlib.lib
.list
; Resident segment that holds the TSR code:
ResidentSeg     segment para public 'Resident'
assume  cs:ResidentSeg
ds:nothing
; The following variable counts the number of keyboard interrupts

KeyIntCnt       word    0

; These two variables contain the original INT 9 and INT 16h
; interrupt vector values:

OldInt9         dword   ?
OldInt16        dword   ?


; MyInt9-       The system calls this routine every time a keyboard
;               interrupt occus. This routine increments the
;               KeyIntCnt variable and then passes control on to the
;               original Int9 handler.

MyInt9          proc    far
inc     ResidentSeg:KeyIntCnt
jmp     ResidentSeg:OldInt9
MyInt9          endp




; MyInt16-      This is the passive component of this TSR. An
;               application explicitly calls this routine with an
;               INT 16h instruction. If AH contains 0FFh
this
;               routine returns the number of keyboard interrupts
;               in the AX register. If AH contains any other value

;               this routine passes control to the original INT 16h
;               (keyboard trap) handler.

MyInt16         proc    far
cmp     ah
0FFh
je      ReturnCnt
jmp     ResidentSeg:OldInt16    ;Call original handler.

; If AH=0FFh
return the keyboard interrupt count

ReturnCnt:      mov     ax
ResidentSeg:KeyIntCnt
iret
MyInt16         endp


ResidentSeg     ends



cseg            segment para public 'code'
assume  cs:cseg
ds:ResidentSeg

Main            proc
meminit

mov     ax
ResidentSeg
mov     ds
ax
mov     ax
0
mov     es
ax

print
byte    "Keyboard interrupt counter TSR program"
cr
lf
byte    "Installing...."
cr
lf
0

; Patch into the INT 9 and INT 16 interrupt vectors. Note that the
; statements above have made ResidentSeg the current data segment

; so we can store the old INT 9 and INT 16 values directly into
; the OldInt9 and OldInt16 variables.

cli                             ;Turn off interrupts!
mov     ax
es:[9*4]
mov     word ptr OldInt9
ax
mov     ax
es:[9*4 + 2]
mov     word ptr OldInt9+2
ax
mov     es:[9*4]
offset MyInt9
mov     es:[9*4+2]
seg ResidentSeg

mov     ax
es:[16h*4]
mov     word ptr OldInt16
ax
mov     ax
es:[16h*4 + 2]
mov     word ptr OldInt16+2
ax
mov     es:[16h*4]
offset MyInt16
mov     es:[16h*4+2]
seg ResidentSeg
sti                             ;Okay
ints back on.

; We're hooked up
the only thing that remains is to terminate and
; stay resident.

print
byte    "Installed."
cr
lf
0

mov     ah
62h                 ;Get this program's PSP
int     21h                     ; value.

mov     dx
EndResident         ;Compute size of program.
sub     dx
bx
mov     ax
3100h               ;DOS TSR command.
int     21h
Main            endp
cseg            ends

sseg            segment para stack 'stack'
stk             db      1024 dup ("stack ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       db      16 dup (?)
zzzzzzseg       ends
end     Main

Here's the application that calls MyInt16 to print the number of keystrokes:

; This is the companion program to the keycnt TSR.
; This program calls the "MyInt16" routine in the TSR to
; determine the number of keyboard interrupts. It displays
; the approximate number of keystrokes (keyboard ints/2)
; and quits.

.xlist
include         stdlib.a
includelib      stdlib.lib
.list

cseg            segment para public 'code'
assume  cs:cseg
ds:nothing

Main            proc
meminit

print
byte    "Approximate number of keys pressed: "
0
mov     ah
0FFh
int     16h
shr     ax
1           ;Must divide by two.
putu
putcr
ExitPgm

Main            endp
cseg            ends

sseg            segment para stack 'stack'
stk             db      1024 dup ("stack ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       db      16 dup (?)
zzzzzzseg       ends
end     Main

Chapter Eighteen (Part 1)

Table of Content

Chapter Eighteen (Part 3)

Chapter Eighteen: Resident Programs (Part 2)
29 SEP 1996