1

I'm writing a simple TSR program but I get error.

I try to execute it by Int 90H but for some reason it's crashed.

I'm new with TSR so the problem might be simple.

TSR:

;   Copy non-small letters

.model tiny
.code
    ORG 100H
start:
    push bp
    push si
    push cx
    push bx
;   save registers
    mov bp, sp
    sub sp, cx
    sub sp, 1 ; for $
    mov di, bp
    mov si, bx
copy:
    cmp [si], 'a'
    jl  bad
;   not small letter
    cmp [si], 'z'
    jg  bad
;   not small leter
;   good
    mov ax, [si]
    mov [bp], ax
    dec bp
bad:
    inc si
loop copy
    mov [bp-1],'$'
    mov ah, 09
    mov dx, di
    int 21H
install:
    mov al, 90H
    mov ah, 25H
    mov dx, offset start
    int 21H
finish: 
    pop bx
    pop cx
    pop si
    pop bp
;   ^ restore registers
    mov ah, 31
    int 21H
    iret
;   end
end start

Main program:

.model small
.stack 64
.data
    string  db  "Hey There"
.code
start:
    lea bx, string
    mov cx, 09
    int 90H
;   end
    mov ah, 4ch
    int 21H
end start

Do you know why my program crashes?

nrz
  • 10,435
  • 4
  • 39
  • 71
iLoveC
  • 97
  • 6
  • 12
  • I have exam next week and I know NOTHING about TSR .. I M-U-S-T your help!! – iLoveC Aug 22 '12 at 05:33
  • 1
    Wait, this is for school? Find a better teacher (or a better school). TSRs have been functionally obsolete since around the release of Windows 95. Nobody (except your teacher?) has cared about them for the last **15+ years**. –  Aug 22 '12 at 05:50
  • No .. It's for college. I really don't care about it too, I'm not using Assembly , but for this moment I have to know this. I don't want to fail the exam secondly and take this course again. please guys - It's really important to me. – iLoveC Aug 22 '12 at 06:01
  • @duskwuff Apparently, DOS (e.g. DosBox on Linux) and Turbo C++ are still used in India's schools to teach programming. – Alexey Frunze Aug 22 '12 at 06:23
  • It's an opportunity to learn some x86 assembly, interrupts and TSRs. – Alexey Frunze Aug 22 '12 at 06:26
  • You'll need to separate the interrupt handler from the main TSR program block (i.e.: to a separate function). Stack, registers and flags should be preserved before exitting the interrupt handler. DOS interrupt hooking isn't that simple also. You'll have to watch out for *In-DOS* flag since you can't call most *Int 21h* services while DOS is busy. So you might want to use a BIOS interrupt instead, to display the text. – Jay Aug 22 '12 at 08:05
  • @Jay Thanks.. but, what do you mean "You'll need to separate the interrupt handler from the main TSR program block"? – iLoveC Aug 22 '12 at 20:33
  • @Alexey - It's not an "opportunity" really, as it is not very useful. I haven't done this since 1985, and don't want to learn how to tune the engine on a Ford Model T either. – Bo Persson Aug 23 '12 at 19:33
  • @BoPersson It may be not an opportunity for you, if you already know all of it and aren't interested in it. I find learning what makes things tick interesting (sometimes even fascinating) and empowering. Interrupts and assembly language are among those things. Learning them made me a better programmer. – Alexey Frunze Aug 23 '12 at 20:06
  • @Alexey - I don't know how to do this, beause I have forgotten. It hasn't been useful for decades, so why try to teach it to new students? Knowing assembly is good, knowing PC-DOS is not. Learning 16-bit assembly *now* is not useful at all! – Bo Persson Aug 23 '12 at 20:12
  • @BoPersson 16-bit assembly does not consist of only manipulating x86 segments. There is still something useful in it now. And segments exist not only the x86. Speaking of decades, in the past decade I have programmed other CPUs (Texas Instruments' DSPs, to be precise) with mechanisms similar to segments. The x86 knowledge was handy there just as was the Z80 knowledge handy for the x86 and you can probably say Z80 is more dead than PC/MS-DOS. And yet, it still has its share in the embedded market and there are even improved versions like eZ80. – Alexey Frunze Aug 23 '12 at 20:37
  • 16 bit knowledge might have been useful as it helped you understanding similar DSPs faster. But even in this background it is not useful at all _now_ - the time investment for learning 16 bit x86 + learning the DSP is surely higher the learning the DSP without prior knowledge, because there is so much now useless bloat in 16 bit MSDOS. – Gunther Piez Aug 24 '12 at 10:21
  • Unfortunately Indian colleges seem to be stuck in the 1980s and so we see lots of homework questions on SO about 8086/8088, 16 bit, MS-DOS, TSRs, Turbo C, etc. – Paul R Aug 27 '12 at 21:14

2 Answers2

0

I wrote a TSR debugger (kind-of) for DOS a more than ten years ago, so I may have forgot something.

Anyway, your interrupt handler you must not assume anything else except that cs points to the segment of your interrupt handler and ip (obviously) points to your interrupt code, that's all you have, and you must not modify anything else in your interrupt handler (except what you specifically want to modify). You have to store all the registers you use, but you cannot just push them to the stack, because you cannot assume that there's any stack left. So make sure to reserve enough memory to store all registers you modify in your interrupt handler, and when you save the registers remember to use cs as segment register, not the default ds, nor es, fs, gs or ss, because they all may point wherever in the memory, and certainly not to any chunk of memory reserved to your TSR. Storing flags in a good idea too.

int 21h calls usually should be avoided in an interrupt handler. You can use BIOS calls (int 10h) or direct writing to video memory (but check the video mode first if you write to video memory in a TSR). Anyway, writing to video memory in a TSR may cause problems, because you don't know how the program that's currently running uses it.

If you want to be sure that no other interrupt is executed during your own interrupt handler, cli in the beginning of your interrupt handler blocks most interrupts and IMHO is a good idea. Remember to allow interrupts by sti just before iret.

nrz
  • 10,435
  • 4
  • 39
  • 71
0

Before we return from our interrupt service routine(ISR) with the iret instruction, we have to send an "end of interrupt"-signal(EOI) with "mov al,020h" + "out 20h,al" to the first programmable interrupt controller(PIC 1; 8259A).

Another method is to jump far to the old ISR instead of sending an EOI and to return with iret.

;---------------

Ralf Browns x86/MSDOS Interrupt List(RBIL)
http://www.pobox.com/~ralf
http://www.pobox.com/~ralf/files.html
ftp://ftp.cs.cmu.edu/afs/cs.cmu.edu/user/ralf/pub/

RBIL->inter61d.zip->PORTS.A
----------P0020003F--------------------------
PORT 0020-003F - PIC 1 - PROGRAMMABLE INTERRUPT CONTROLLER (8259A)
SeeAlso: PORT 00A0h-00AFh"PIC 2",INT 08"IRQ0",INT 0F"IRQ7"
....for more details look into the RBIL please..

;------------

For to become a TSR we have to use INT 27h for terminating with the ISR-part of our application stay resident.

RBIL->inter61c.zip->INTERRUP.K
--------D-27---------------------------------
INT 27 - DOS 1+ - TERMINATE AND STAY RESIDENT
DX = number of bytes to keep resident (max FFF0h)
CS = segment of PSP
Return: never
Notes: this is an obsolete call
INT 22, INT 23, and INT 24 are restored from the PSP
does not close any open files
the minimum number of bytes which will remain resident is 110h for
DOS 2.x and 60h for DOS 3.0+; there is no minimum for DOS 1.x, which
implements this service in COMMAND.COM rather than the DOS kernel
SeeAlso: INT 21/AH=31h

;----------

It think it is not a good idea to use a software interrupt calling within our ISR. So i prefer direct writing to the video memory instead, example to write some numbers in the upper rigth corner of the screen for to show the current time.

;------

For to set and for to get a interrupt vector:

RBIL->inter61b.zip->INTERRUP.F
--------D-2125-------------------------------
INT 21 - DOS 1+ - SET INTERRUPT VECTOR
AH = 25h
AL = interrupt number
DS:DX -> new interrupt handler
Notes: this function is preferred over direct modification of the interrupt
vector table
some DOS extenders place an API on this function, as it is not
directly meaningful in protected mode
under DR DOS 5.0-6.0, this function does not use any of the
DOS-internal stacks and may thus be called at any time; however,
under Novell DOS 7.0 - DR-DOS 7.02, this function was not reentrant.
Since 1998/05/29, DR-DOS 7.03 no longer uses any internal stacks and
tests for this function much earlier, to allow a minimal stack usage
of just two words in addition to the IRET frame, allowing it to be
called from INT 21h functions, specificially device drivers. This
fixes the MCS SMB client
Novell NetWare (except the new DOS Requester) monitors the offset of
any INT 24 set, and if equal to the value at startup, substitutes
its own handler to allow handling of network errors; this introduces
the potential bug that any program whose INT 24 handler offset
happens to be the same as COMMAND.COM's will not have its INT 24
handler installed
SeeAlso: AX=2501h,AH=35h

--------D-2135-------------------------------
INT 21 - DOS 2+ - GET INTERRUPT VECTOR
AH = 35h
AL = interrupt number
Return: ES:BX -> current interrupt handler
Note: under DR DOS 5.0+, this function does not use any of the DOS-internal
stacks and may thus be called at any time
SeeAlso: AH=25h,AX=2503h

Another method for to set an interrupt vector is to write to the memory location of the vector itself:
Example for to set the Timerinterrupt(8) to our new ISR starting at the label "TIMER_INT":

mov ax,0
mov ds,ax
cli
mov WORD PTR ds:[8*4],OFFSET TIMER_INT
mov WORD PTR ds:[8*4+2],cs
sti

Dirk