Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help Writing TSR Program(s) in NASM Assembly for DOS

I've been trying to write TSR (Terminate-Stay-Resident) programs (in general) in Assembly (16-bit) for MS-DOS. I've read through a Wikipedia page on TSR and also a page on using it specifically in DOS (but it seems to be teaching it in C and not Assembly directly). I've looked at a site with tons of DOS interrupt documentation and find this one, this one, and another most relevant to TSR programs. I can't post all of the links because as a new user I can have up to 2 hyperlinks on a post.

So, I've tried writing a (seemingly) very simple TSR program in real mode flat model (.COM file format) in NASM. Here's the code:

[BITS 16]
[ORG 0x0100]

[SECTION .text]

Start:
; Get current interrupt handler for INT 21h
mov AX,3521h                ; DOS function 35h GET INTERRUPT VECTOR for interrupt 21h
int 21h                     ; Call DOS  (Current interrupt handler returned in ES:BX)

mov WORD [v21HandlerSegment],ES     ; Store the current INT 21h handler segment
mov WORD [v21HandlerOffset],BX      ; Store the current INT 21h handler offset

; Write new interrupt handler for INT 21h
mov AX,2521h                ; DOS function 25h SET INTERRUPT VECTOR for interrupt 21h
mov DX,TSRStart             ; Load DX with the offset address of the start of this TSR program
;   DS already contains the segment address, it is the same as CS in this .COM file
int 21h                     ; Override the INT 21h handler with this TSR program

; The TSR program will be called even when this portion uses INT 21h to terminate and stay resident
mov AX,3100h                ; DOS function TSR, return code 00h
mov DX,00FFh                ; I don't know how many paragraphs to keep resident, so keep a bunch
int 21h                     ; Call our own TSR program first, then call DOS

TSRStart:
push WORD [v21HandlerSegment]       ; Push the far address of the original 
push WORD [v21HandlerOffset]        ;   INT 21h handler onto the stack
retf                                ; Jump to it!


[SECTION .data]
v21HandlerSegment dw 0000h
v21HandlerOffset  dw 0000h

When I assemble this and execute it inside DOS, instead of returning back to the DOS prompt it hangs the system (no activity occurs except the hardware cursor just blinks below the last prompt). I guess memory garbage might be executing but you get the point.

Could anybody please help to either figure out what the problem with this code is and / or offer general advice for coding TSR's in DOS? Thanks in advance, any help is very much appreciated!

like image 236
Alex Ozer Avatar asked Jul 28 '11 04:07

Alex Ozer


People also ask

How do you write a TSR program?

In our TSR code first we have to capture the interrupt ie we have to get it's address where in the memory it is stored then we have to replace the address with the address of our code and then within our code we have to call the actual procedure after or before executing our code.

What is TSR Assembly?

The original call, INT 27h, is called "terminate but stay resident", hence the name "TSR". Using this call, a program can make up to 64 KB of its memory resident. MS-DOS version 2.0 introduced an improved call, INT 21h/31h ('Keep Process'), which removed this limitation and let the program return an exit code.

What are TSR programs demonstrate by giving a suitable C program?

TSR stands for Terminate and Stay Resistant. A TSR program installs itself (or gets installed) and will stay permanent in the system even if the program returns from its main routine.

What is TSR in C?

A terminate and stay resident (TSR) program is one that is set up to be loaded and then remain in computer memory so that it is quickly accessible when a user presses a certain keyboard combination. TSR programs are used in Disk Operating Systems and perhaps other non-task operating systems.


1 Answers

I figured it out. After looking through a couple more sources, I discovered that this code:

push WORD [v21HandlerSegment]       ; Push the far address of the original 
push WORD [v21HandlerOffset]        ;   INT 21h handler onto the stack

needs to be something like this:

push WORD [CS:v21HandlerSegment]       ; Push the far address of the original 
push WORD [CS:v21HandlerOffset]        ;   INT 21h handler onto the stack

because those memory references are referencing from the data segment, which isn't set up from the caller of the TSR. So basically I was referencing data from something else's data block...

This can also be accomplished by putting CS in DS (and then putting DS's original value back) like this:

push DS
push CS
pop DS
; Memory references....
pop DS
like image 71
Alex Ozer Avatar answered Oct 31 '22 01:10

Alex Ozer