home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1989
/
02
/
menico.asc
< prev
next >
Wrap
Text File
|
1989-01-04
|
11KB
|
401 lines
_Debugging TSR Programs_
by Costas Menico
[LISTING ONE]
;
; Set TABS to 8 for viewing with editor.
;
;-------------------------------------------------------;
; KEYSWAP program ;
; By Costas Menico. ;
; Software Bottling Company ;
; 6600 Long Island Expressway ;
; Maspeth, N.Y. 11378 ;
; 718-458-3700 ;
; This program will swap the F8 & F10 key for the ;
; Up and Down arrow keys. ;
; Demonstrator program for debugging memory resident ;
; program using Turbo Debugger. ;
;-------------------------------------------------------;
.model small
; Set key values.
; For the SCAN and ASCII codes of any other keys, see the BIOS manual
f8key equ 4200h ; define the F8 key
f10key equ 4400h ; define the F10 key
upkey equ 4800h ; define the up arrow key
downkey equ 5000h ; define the down arrow key
DOSCALL equ <int 21h> ; DOS interrupt call
LOADSEG MACRO segr1, segr2 ; Load segment register
push segr2 ; macro.
pop segr1
ENDM
; Publics area
public start, oldint16, int16handler, exit, test_for_key
public load_tsr, tsr_terminate, chain_vector, f10pressed
; Start Code
.code
assume cs:_text, ds:_text, es:_text, ss:nothing
;-------------------;
; Our program start ;
;-------------------;
org 100h ; COM file starting program address.
start:
jmp load_tsr ; Load our program resident.
; Data area. Since this is COM file all data
; and code are in the Code segment.
evendata
oldint16 dd 0 ; Area for old interrupt 16h vector.
stackbot dw 128 dup('?'); Our stack bottom.
stacktop equ $-2 ; Our stack top.
;-----------------------------------------------;
; Entry to keyboard handler. ;
; We get here when any application or DOS ;
; executes an INT 16h. ;
; Input: AH=0 - Get a key ;
; Output: The key in AX ;
; Input: AH=1 - Check for key ;
; Ouput: The available key in AX ;
; Input: AH=2 - Get shift flags ;
; Output: The shift flags in AL ;
;-----------------------------------------------;
int16handler proc far
pushf ; Save flags status.
or ah, ah ; Are we getting a key?
je test_for_key ; Yes - goto to test for F10.
popf ; No - pop flags and
jmp cs:oldint16 ; jump to old interrupt handler.
; Get a pressed key and test if it was
; and F10
test_for_key:
popf ; Pop the original flags.
pushf ; Push them again
call cs:oldint16 ; and simulate INT 16h.
pushf ; Save flags.
cmp ax, f10key ; is this an F10 key?
jne is_it_f8 ; no - check for F8.
f10pressed:
mov ax, downkey ; yes - set swap key in ax.
jmp short exit
is_it_f8:
cmp ax, f8key ; is this an F8 key?
jne exit ; no - exit
mov ax, upkey ; yes - set swap key in ax.
exit:
popf ; Pop the saved flags.
iret ; Return to caller with key in ax.
int16handler endp
IFDEF DEBUG
; Assemble this section to debug the TSR with Turbo Debugger.
; You must assemble with the /DDEBUG option.
include tsrdebug.asm
ENDIF
;===============================================;
; Load KEYSWAP, and terminate but stay resident.;
; Once KEYSWAP is loaded all code from here on ;
; is discarded. ;
;===============================================;
load_tsr:
; Set SP to our internal stack area
cli ; Do not interrupt while
mov sp, offset stacktop ; stack pointer is being adjusted.
sti ; Now interrupt.
call chain_vector ; Install our keyboard interrupt.
IFDEF DEBUG
; Assemble this section to debug the TSR with Turbo Debugger.
; You must assemble with the /DDEBUG option.
call tsr_simulate
ELSE
; Assemble this section to run without the debugging.
call tsr_terminate
ENDIF
;-----------------------------;
; Save old interrupt 16 vector;
; and point it to our handler ;
;-----------------------------;
chain_vector proc uses ax bx dx es
mov ax, 3516h ; Get the int 16h keyboard vector.
DOSCALL
mov word ptr oldint16, bx; Save old vector in our data area.
mov word ptr oldint16[2], es
mov ax, 2516h ; Set the new vector of our
mov dx, offset int16handler; interrupt 16h keyboard handler.
DOSCALL
ret
chain_vector endp
;-----------------------------;
; Terminate and stay resident ;
;-----------------------------;
tsr_terminate proc
mov dx, offset load_tsr ; Get offset address of program
mov cl, 4 ; code to discard.
shr dx, cl ; Convert to pargraphs.
inc dx ; Round off to the next paragraph.
mov ax, 3100h ; Terminate & stay resident function.
DOSCALL
tsr_terminate endp
@CurSeg ends
end start
[LISTING TWO]
;---------------------------------------------------------------;
; Include file TSRDEBUG.ASM ;
; ;
; Assemble this code if you will debug with Turbo Debugger ;
; You must assemble with the /DDEBUG option. ;
;---------------------------------------------------------------;
public param, command_com
public tsr_simulate, unchain_vector, int9handler
BREAKPOINT equ <int 3> ; Debugger break point
ctrlflag equ 4 ; Ctrl key BIOS indicator flag.
enterscan equ 28 ; Scan code for Enter key.
kbdflags equ 417h ; BIOS keyboard flags location
; Load & Execute parameter block structure
execparam struc
envstr_addr dw 0 ; Environment pointer
cmdline_ofs dw 0 ; Offset to command line.
cmdline_seg dw 0 ; Segment to command line.
fcb1_ofs dw 0 ; Offset of fcb1.
fcb1_seg dw 0 ; Segment of fcb1
fcb2_ptr dw 0 ; Offset of fcb2.
fcb2_seg dw 0 ; Segment of fcb2.
execparam ends
oldint9 dd 0 ; Area for old int 9 vector.
paramvals equ <0,offset cmd_line,?,offset fcb1,?,offset fcb2,?>
;
; Shows below how the data above is initialized.
;
comment ^
0, ; Use current environment
offset cmd_line,? ; Point to command line.
offset fcb1,? ; Offset & Seg of fcb1.
offset fcb2,? ; Offset & Seg of fcb2.
^
param execparam <paramvals>
command_com db 'c:\command.com',0
cmd_line db 0, 0dh ; Command line is null.
savess dw 0 ; Save SS here.
savesp dw 0 ; Save SP here.
fcb1 db 16 dup(0) ; Blank area for FCB1
fcb2 db 27 dup(0) ; Blank area for FCB2
;-----------------------------------------------;
; Int 9 handler. Ctrl-Enter key check. ;
; Each time a key is pressed it is checked ;
; if the Ctrl & Enter key were pressed ;
; simultaneously. If they were then we ;
; interrupt Turbo Debugger ;
;-----------------------------------------------;
int9handler proc far
pushf ; Save the flags
push ax ; Save ax
push ds ; Save dx
xor ax, ax ; Point DS to segment 0
mov ds, ax
; Is the Ctrl key pressed?
test byte ptr ds:[kbdflags], ctrlflag
je exitint9 ; No - call old int 9 & exit.
in al, 60h ; Yes - get the scan code of key.
cmp al, enterscan ; Is it the Enter key?
je breakkey ; Yes - go to break Turbo Debug
exitint9: ; No - call old int 9 & exit
pop ds ; Pop ds & ax before jump.
pop ax
popf ; Pop flags
jmp cs:oldint9 ; Jump to the old int 9
breakkey:
pop ds ; Pop ds & ax before jump.
pop ax
popf ; Pop flags
in al, 61h ; Reset the keyboard controller
mov ah, al ; for next key.
or al, 80h
out 61h, al
xchg ah, al
out 61h, al
mov al, 20h ; Enable interrupts
out 20h, al
BREAKPOINT ; Execute our break point.
; Turbo Debugger STOPS HERE!.
; To find out what the program
; was doing press F7 (Trace)
; twice.
iret
int9handler endp
;---------------------------------------;
; Simulate Terminate and stay resident ;
; Frees unecessary memory and loads & ;
; executes COMMAND.COM ;
;---------------------------------------;
tsr_simulate proc
; Free unused memory.
LOADSEG ES, CS ; Point ES to our segment.
mov bx, offset load_tsr ; Get offset address of program
mov cl, 4 ; code to discard.
shr bx, cl
inc bx ; round off to the next paragraph
mov ah, 4ah ; Shrink allocated block function
DOSCALL ; call DOS
; Save stack registers
mov savess, ss ; Save stack segment.
mov savesp, sp ; Save stack pointer.
; Chain unto int 9 for debugger break key.
mov ax, 3509h ; Get the int 9 keyboard vector.
DOSCALL
mov word ptr oldint9, bx; Save old vector in our data area.
mov word ptr oldint9[2], es
mov ax, 2509h ; Set the new vector of our
mov dx, offset int9handler; interrupt 9 keyboard handler.
DOSCALL
; Load and execute COMMAND.COM
LOADSEG ES, CS ; Point ES to our segment
mov dx, offset command_com; Point to COMMAND.COM file path.
mov bx, offset param ; Get address of param block.
mov [bx].cmdline_seg, ds; Get segment of the command line.
mov [bx].fcb1_seg, ds ; Get segment of fcb1
mov [bx].fcb2_seg, ds ; Get segment of fcb2
mov ax, 4b00h
DOSCALL ; Load and execute COMMAND.COM.
; Upon return form load and execute, all registers are
; destroyed and the necessary ones, must be recovered.
cli ; Turn interrupts off.
mov ss, cs:savess ; Recover stack segment.
mov sp, cs:savesp ; Recover stack pointer.
sti
LOADSEG DS, CS ; Recover data segment
; Unchain all our handlers, and terminate program.
mov ax, 2509h ; Unchain our int 9 vector and put
lds dx, oldint9 ; original in.
DOSCALL
call unchain_vector ; Unchain our keyboard handler
mov ax, 4c00h ; Terminate program.
DOSCALL
tsr_simulate endp
;----------------------------------------;
; Unchain vectors before exiting debugger ;
;----------------------------------------;
unchain_vector proc uses ds ax
mov ax, 2516h ; Unchain our vector and put
lds dx, oldint16 ; original in.
DOSCALL
ret
unchain_vector endp
[Example 1: Typical structure of a TSR program]
; This portion remains resident
tsr data
tsr interrupt handlers
tsr other programs
; This portion is freed when the DOS Terminate
; and Stay resident function is executed.
data area
load entry point:
create stack
call other check routines
(e.g. DOS version, parameters, available memory, etc.)
chain tsr interrupt handlers
determine size of tsr to keep
call DOS TSR function
end
[Example 2: DOS functions used in KEYSWAP]
Note: The following is a list of the DOS INT 21h functions used
in KEYSWAP. Remember that if any DOS function returns with the
CARRY flag set, the function had a problem. Usually the error
reason is returned in the AX register. For more information, see
the DOS Technical Reference manual, or one of the dozens of books
on the subject.
Set the vector of interrupt:
Input: AH = 25h, AL = interrupt #
DS:DX = segment & offset value of new interrupt handler.
Terminate but stay resident:
Input: AH = 31h, AL = errorlevel
DX = # of paragraphs to keep.
Get the vector of interrupt:
Input:
AH = 35h, AL = interrupt #
Output:
ES:BX = segment & offset value of the current interrupt handler.
Shrink allocated memory:
Input: AH = 4Ah, ES = Segment to shrink
BX = paragraphs to keep.
Load & Execute:
Input: AH = 4Bh, AL = 0 (If AL = 3 then it only loads)
ES:BX = segment and offset of params block
(for param block format see the program)
DS:DX = segement & offset of command (ASCIIZ string).
Output: None, but all registers including SS and SP are
destroyed.
Terminate program:
Input: AH = 4Ch, AL = errorlevel