[comp.os.msdos.programmer] stealing an interrupt

TOMIII@MTUS5.BITNET (Thomas Dwyer III) (12/18/90)

Hi there.  Would some kind soul please tell me why my machine hangs when
I run this TSR?  What am I doing wrong?

------ Code Begins ------

INT_NUM equ     9h

code    segment
        org     0100h
        assume  cs:code,ds:code,es:code

start:
        mov     ah,35h                          ; Get int vector
        mov     al,INT_NUM
        int     21h

        mov     word ptr [old_int+2],es         ; Save old vector
        mov     word ptr [old_int],bx

        mov     ah,25h                          ; Set int vector
        mov     al,INT_NUM
        mov     dx,offset new_int
        int     21h

        mov     dx,50h
        mov     ax,3100h
        int     21h


new_int proc    far
        jmp     short go

old_int dd      ?

go:
        jmp     [old_int]                       ; Jump to old int routine
new_int endp


code    ends
        end     start

----- Code Ends ------

Thank you,
Thomas Dwyer III                        Email: tomiii@mtu.edu
Network Programmer                             tomiii@mtus5.BITNET
Computing Technology Services           Voice: (906) 487-2110
Michigan Technological University       Fax:   (906) 487-2787

ekalenda@cup.portal.com (Edward John Kalenda) (12/18/90)

Thomas Dwyer write:
> Hi there.  Would some kind soul please tell me why my machine hangs when
> I run this TSR?  What am I doing wrong?

The first problem that comes to mind is that your interrupt handling
routine is doing a jump to a location pointed to by an area in your
data segment. You should use JMP cs:[oldint] since the data segment
at the time the interrupt occurs will be that of the program running,
not your TSR. You're probobly jumping off into space somewhere based on
the value of ds:[oldint] in the current program's frame of reference.

Ed
ekalenda@cup.portal.com

brandis@inf.ethz.ch (Marc Brandis) (12/18/90)

In article <90351.150210TOMIII@MTUS5.BITNET> TOMIII@MTUS5.BITNET (Thomas Dwyer III) writes:
>Hi there.  Would some kind soul please tell me why my machine hangs when
>I run this TSR?  What am I doing wrong?

[some stuff deleted]
>        assume  cs:code,ds:code,es:code
....
>        mov     word ptr [old_int+2],es         ; Save old vector
>        mov     word ptr [old_int],bx

Here, there is a rather unsafe assumption that ds points to the code segment
after DOS has been called. You should better set ds explicitly to code (e.g.
by push cs, pop ds) or use an segment prefix for cs. However, it is correct
in this place that ds points to code, it is just unsafe.

>        mov     ah,25h                          ; Set int vector
>        mov     al,INT_NUM
>        mov     dx,offset new_int

Once again, it would be better to set ds explicitly to the code segment.

....
>old_int dd      ?
>        jmp     [old_int]                       ; Jump to old int routine

Here lies the real problem. As this code is called inside an interrupt, the
assumption that ds points to code is wrong (!). You can either add a correct
assume statement in front of this code, which would be

		assume cs:code, ds:nothing, es:nothing, ss:nothing

or you can make it explicit that you want a segment prefix for this instruction
and that you want a far call, which is actually what I would suggest. It is
much better to make it explicit what is going on than to rely on the context
given by the assume statements. So try the following statement (the ultra safe
version)

	jmp	dword ptr cs:[old_int]

This should do what you want. 


Marc-Michael Brandis
Computer Systems Laboratory, ETH-Zentrum (Swiss Federal Institute of Technology)
CH-8092 Zurich, Switzerland
email: brandis@inf.ethz.ch

schmidt@mars.jpl.nasa.gov (Kevin Schmidt) (12/19/90)

In article <90351.150210TOMIII@MTUS5.BITNET> TOMIII@MTUS5.BITNET (Thomas Dwyer III) writes:
>Hi there.  Would some kind soul please tell me why my machine hangs when
>I run this TSR?  What am I doing wrong?
>
>------ Code Deleted ------
>
Code that was here got INT 9 vector and put it in old_int.  It then set
the INT 9 vector to point to new_int.
>
>new_int proc    far
>        jmp     short go
>
>old_int dd      ?
>
>go:
>        jmp     [old_int]                       ; Jump to old int routine
>new_int endp
>
>----- Code Ends ------
>
Everything looks fine except that the last jump (jmp [old_int]) has two
problems.  First the jump must include a segment override so that the
data segment (ds) is not used in calculating the address of old_int.
Second you must insure that it is a far jump.  Thus the line should read:

   jmp far cs:[old_int]

If you still can't get it to work, email me and I will send you a sample
of how to attach to INT 9.
_______________________________________________________________________________
        _   ____    _   |                           |
       / / / _  \  / /  | Kevin T. Schmidt          | schmidt@mars.jpl.nasa.gov
      / / / /_/ / / /   | Jet Propulsion Laboratory | schmidt@jems.jpl.nasa.gov
 _   / / / ____/ / /    | 4800 Oak Grove Dr.        |
/ /_/ / / /     / /___  | M/S 301-355               |
\____/ /_/     /______/ | Pasadena, CA  91109       |

valley@uchicago (Doug Dougherty) (12/19/90)

brandis@inf.ethz.ch (Marc Brandis) writes:

>In article <90351.150210TOMIII@MTUS5.BITNET> TOMIII@MTUS5.BITNET (Thomas Dwyer III) writes:
>>Hi there.  Would some kind soul please tell me why my machine hangs when
>>I run this TSR?  What am I doing wrong?

>[some stuff deleted]
>>        assume  cs:code,ds:code,es:code
>....
>>        mov     word ptr [old_int+2],es         ; Save old vector
>>        mov     word ptr [old_int],bx

>Here, there is a rather unsafe assumption that ds points to the code segment
>after DOS has been called. You should better set ds explicitly to code (e.g.
>by push cs, pop ds) or use an segment prefix for cs. However, it is correct
>in this place that ds points to code, it is just unsafe.

Oh, come on.  You can surely assume two things:

	1) DS = CS on entry to a COM program
	2) No DOS call is gonna change DS (unless explicitly stated in
	the documentation; I can't imagine that any do as of this
	writing)

Yes, it is a good idea to be a little paranoid (maybe a lot paranoid)
when doing assembly language programming, but you are taking it too far.

But then again, you probably code in MASM or TASM or something like
that, so it figures you'd be a little paranoid about segment registers...

stever@Octopus.COM (Steve Resnick ) (12/19/90)

In article <90351.150210TOMIII@MTUS5.BITNET> TOMIII@MTUS5.BITNET (Thomas Dwyer III) writes:
>Hi there.  Would some kind soul please tell me why my machine hangs when
>I run this TSR?  What am I doing wrong?
>
>------ Code Begins ------
>
>INT_NUM equ     9h
>
>code    segment
>        org     0100h
>        assume  cs:code,ds:code,es:code
	[Init Code Deleted]
>new_int proc    far
>        jmp     short go
>
>old_int dd      ?
>
>go:
>        jmp     [old_int]                       ; Jump to old int routine

I'm not sure, but I think that this is DS relative. In other words, when
your ISR is called, DS may be pointing elsewhere.

>new_int endp
>
>
>code    ends
>        end     start
>
>----- Code Ends ------

A much better (IMHO) way to do this, is to borrow the interrupt from the
system, call the original ISR, do your own dirty work, and return.
The way I do this in a couple programs is to save the old ISR address
in the same way you have, but call it differently.

new_int proc    far
        jmp     short go

old_int dd      ?

go:	pushf		; Pushing the flags before a FAR call simulates
			; an INT instruction. The ISR being called will
			; then IRET to here.

	call	DWORD PTR cs:[old_isr] 
	.
	.		; Do something usefull here.
	.
	IRET
new_int	endp

This gives you the flexibility of handling the original ISR, as well as
your own code.

Hope this helps....
Steve



	
-- 
----------------------------------------------------------------------------
steve.resnick@f105.n143.z1.FIDONET.ORG - or - apple!camphq!105!steve.resnick
Flames, grammar errors, spelling errrors >/dev/nul
The Asylum OS/2 BBS - (408)263-8017 IFNA 1:143/105.0

lbr@holos0.uucp (Len Reed) (12/20/90)

In article <37017@cup.portal.com> ekalenda@cup.portal.com (Edward John Kalenda) writes:
>Thomas Dwyer write:
=> Hi there.  Would some kind soul please tell me why my machine hangs when
=> I run this TSR?  What am I doing wrong?
=
=The first problem that comes to mind is that your interrupt handling
=routine is doing a jump to a location pointed to by an area in your
=data segment. You should use JMP cs:[oldint] since the data segment
=at the time the interrupt occurs will be that of the program running,
=not your TSR. You're probobly jumping off into space somewhere based on
=the value of ds:[oldint] in the current program's frame of reference.

This analysis is correct but the solution is a little dangerous.  I say
this because I assume you're going to add code rather than leave your
do-nothing skeleton in place. :-)

Rather than putting the explicit "cs:" prefix in you should ensure that
the in-effect "assumes" always match what's in the segment registers.
Having done a lot of driver and TSR programming I can assure you that
using explicit prefix overrides to save coding an "assume" will
eventually lead to problems.  Explicitly marking your assumes informs
the assembler *and* the next programmer what you thought was in the
segment registers.

In your case, before the interrupt handler you should say:
	assume cs:code, ds:nothing, es:nothing, ss:nothing

The assembler will then add the segment prefix for you.  If it's not
addressable you should get an assembly-time error.

BTW, why do you embed your pointer to the saved handler inside your
procedure?  Just say

	; [first part omitted here]
	mov ax,3100h	; terminate and stay resident
	int 21h
	;NOT REACHED

   even			; word-align the data for efficiency
old_int dd ?

	assume cs:code, ds:nothing, es:nothing, ss:nothing
new_int proc far
	jmp [old_int]
new_int endp
-- 
Len Reed
Holos Software, Inc.
Voice: (404) 496-1358
UUCP: ...!gatech!holos0!lbr

stever@Octopus.COM (Steve Resnick ) (12/20/90)

In article <valley.661550344@gsbsun> valley@uchicago (Doug Dougherty) writes:
>brandis@inf.ethz.ch (Marc Brandis) writes:
>
>>In article <90351.150210TOMIII@MTUS5.BITNET> TOMIII@MTUS5.BITNET (Thomas Dwyer III) writes:
>>>Hi there.  Would some kind soul please tell me why my machine hangs when
>>>I run this TSR?  What am I doing wrong?
>
>>[some stuff deleted]
>>>        assume  cs:code,ds:code,es:code
>>....
>>>        mov     word ptr [old_int+2],es         ; Save old vector
>>>        mov     word ptr [old_int],bx
>
>>Here, there is a rather unsafe assumption that ds points to the code segment
>>after DOS has been called. You should better set ds explicitly to code (e.g.
>>by push cs, pop ds) or use an segment prefix for cs. However, it is correct
>>in this place that ds points to code, it is just unsafe.
>
>Oh, come on.  You can surely assume two things:
>
>	1) DS = CS on entry to a COM program
>	2) No DOS call is gonna change DS (unless explicitly stated in
>	the documentation; I can't imagine that any do as of this
>	writing)
>
>Yes, it is a good idea to be a little paranoid (maybe a lot paranoid)
>when doing assembly language programming, but you are taking it too far.
>
>But then again, you probably code in MASM or TASM or something like
>that, so it figures you'd be a little paranoid about segment registers...

Oh come on. I can surely assume one of two things: 

	1) You do not understand interrupts.
	2) You didn't read what the message said.

This code is for an interrupt handler. In an interrupt handler the ONLY
segment address that is known upon entry is the CS register. 
Sorry for the flame, but, please read the posters question(s) before 
responding to them incorrectly. 

Steve

-- 
----------------------------------------------------------------------------
steve.resnick@f105.n143.z1.FIDONET.ORG - or - apple!camphq!105!steve.resnick
Flames, grammar errors, spelling errrors >/dev/nul
The Asylum OS/2 BBS - (408)263-8017 IFNA 1:143/105.0

lbr@holos0.uucp (Len Reed) (12/20/90)

In article <18633@neptune.inf.ethz.ch> brandis@inf.ethz.ch (Marc Brandis) writes:
>In article <90351.150210TOMIII@MTUS5.BITNET> TOMIII@MTUS5.BITNET (Thomas Dwyer III) writes:
>>Hi there.  Would some kind soul please tell me why my machine hangs when
>>I run this TSR?  What am I doing wrong?
>
>[some stuff deleted]
>>        assume  cs:code,ds:code,es:code
>....
>>        mov     word ptr [old_int+2],es         ; Save old vector
>>        mov     word ptr [old_int],bx
>
>Here, there is a rather unsafe assumption that ds points to the code segment
>after DOS has been called. You should better set ds explicitly to code (e.g.
>by push cs, pop ds) or use an segment prefix for cs.
>in this place that ds points to code, it is just unsafe.

Nonsense.  What's unsafe about this?  This is obviously a ".com" TSR: COMs
start with CS=DS=ES=SS.  The assume notes this (although SS is not
listed), and the DOS calls used preserve the DS register, so the DS
register does in fact point to the code.

Why use overrides or pushes and pops when the DS: points where you want
it to?  (And if it doesn't point where you want it to then the assumes
should tell the assembler this.  This is where the bug lies.)

There's no problem, potential or otherwise, here.

>....
>>old_int dd      ?
>>        jmp     [old_int]                       ; Jump to old int routine
>
>Here lies the real problem. As this code is called inside an interrupt, the
>assumption that ds points to code is wrong (!). You can either add a correct
>assume statement in front of this code, which would be
>
>		assume cs:code, ds:nothing, es:nothing, ss:nothing
>
>or you can make it explicit that you want a segment prefix for this instruction
>and that you want a far call, which is actually what I would suggest. It is
>much better to make it explicit what is going on than to rely on the context
>given by the assume statements. So try the following statement (the ultra safe
>version)
>
>	jmp	dword ptr cs:[old_int]

Well, maybe explicit is better, but if you're really trying to code something
well your assumes should be correct.  Put the assume statement in.
What I'm saying is that it's fine to give the assembler more information
than it needs, but you shouldn't give it wrong information (i.e., not
changing the assume) and then override that wrong information with a
segment prefix.

Eventually this code will get expanded to do something useful.  Having
the assumes wrong is a recipe for future bugs and is confusing to
anyone who might later read this code.

I assume that your explicit adding of "dword ptr" in the above jump is
intended to document that this is a far jump.  (The assembler knows that
old_int is a doubleword so "dword ptr" is unecessary.)  Some assembler
won't take the format you used; you have to say
	jmp	cs: dword ptr [old_int]
-- 
Len Reed
Holos Software, Inc.
Voice: (404) 496-1358
UUCP: ...!gatech!holos0!lbr

lbr@holos0.uucp (Len Reed) (12/20/90)

In article <1990Dec18.163810.21268@jato.jpl.nasa.gov> schmidt@mars.UUCP (Kevin Schmidt) writes:

>Everything looks fine except that the last jump (jmp [old_int]) has two
>problems.  First the jump must include a segment override so that the
>data segment (ds) is not used in calculating the address of old_int.
>Second you must insure that it is a far jump.  Thus the line should read:
>
>   jmp far cs:[old_int]

Elsewhere I've noted that you should change the assumes.  Overriding the
segment is fine, too, if you wish.  You don't need to tell the assembler
that this is a far jump, though, since it knows this because old_int is
doubleword.  If you wish to make everything explicit, though, the above
form is incorrect.  Try

	jmp cs:dword ptr [old_int]	; far jump indirect to saved handler
-- 
Len Reed
Holos Software, Inc.
Voice: (404) 496-1358
UUCP: ...!gatech!holos0!lbr

valley@uchicago (Doug Dougherty) (12/20/90)

stever@Octopus.COM (Steve Resnick ) writes:

>>>[some stuff deleted]
>>>>        mov     word ptr [old_int+2],es         ; Save old vector
>>>>        mov     word ptr [old_int],bx
>>
>>>Here, there is a rather unsafe assumption that ds points to the code segment
>>>after DOS has been called. You should better set ds explicitly to code (e.g.
>>>by push cs, pop ds) or use an segment prefix for cs. However, it is correct
>>>in this place that ds points to code, it is just unsafe.
>>
>>Oh, come on.  You can surely assume two things:
>>
>>	1) DS = CS on entry to a COM program
>>	2) No DOS call is gonna change DS (unless explicitly stated in
>>	the documentation; I can't imagine that any do as of this
>>	writing)

>Oh come on. I can surely assume one of two things: 

>	1) You do not understand interrupts.	(I do too)
>	2) You didn't read what the message said.	(I did too)(

>This code is for an interrupt handler. In an interrupt handler the ONLY
>segment address that is known upon entry is the CS register. 
>Sorry for the flame, but, please read the posters question(s) before 
>responding to them incorrectly. 

>Steve


Yes, this is turning into a flame war and should probably be moved to
talk.msdos (or some such)

Nevertheless, I am well aware of the need for a CS: override in the
interrupt handler itself (unless & until you set DS = CS)

I have written several TSRs and several device drivers, so I ain't no newbie.

However, you seemed to be saying that you thought it was a good idea to
(repetitively) set DS to CS *IN THE MAIN "BOOSTER"* (i.e., non-resident)
part of the program.  In fact, the two lines of code quoted above follow
immediately a INT 21, fn 35 call, which sets ES:BX equal to the current
interrupt value.  Surely that call is going to leave DS alone.
(It would be unwise [because of re-entrancy considerations], not to
mention pointless, to call INT 21, fn 35 inside the resident part of the TSR)

Gottit?  Good.

brandis@inf.ethz.ch (Marc Brandis) (12/20/90)

In article <1990Dec19.174402.5882@holos0.uucp> lbr@holos0.uucp (Len Reed) writes:
>In article <18633@neptune.inf.ethz.ch> brandis@inf.ethz.ch (Marc Brandis) writes:
>>[some stuff deleted]
>>>        assume  cs:code,ds:code,es:code
>>....
>>>        mov     word ptr [old_int+2],es         ; Save old vector
>>>        mov     word ptr [old_int],bx
>>
>>Here, there is a rather unsafe assumption that ds points to the code segment
>>after DOS has been called. You should better set ds explicitly to code (e.g.
>>by push cs, pop ds) or use an segment prefix for cs.
>>in this place that ds points to code, it is just unsafe.
>
>Nonsense.  What's unsafe about this?  This is obviously a ".com" TSR: COMs
>start with CS=DS=ES=SS.  The assume notes this (although SS is not
>listed), and the DOS calls used preserve the DS register, so the DS
>register does in fact point to the code.
>
>Why use overrides or pushes and pops when the DS: points where you want
>it to?  (And if it doesn't point where you want it to then the assumes
>should tell the assembler this.  This is where the bug lies.)

It looks like my posting is starting a flame war, which the topic is definitely
not worth. Still I want to add a comment.

    Unless you had deleted it up there, you would see that I said that DS points
    to the right segment there. I certainly know this, and I would not add the
    code to set it explicitly to the code segment. However, from the listing
    given, I assumed that the original poster was not experienced in assembly
    language, so I wanted to show him a piece of code that works under all
    circumstances. Although there is no DOS call that changes DS, there are
    some BIOS calls that do. If you do not have good documentation about it
    (and lots of people do just a little bit of assembly programming without
    any documentation but instead copying from other's sources), it is best to
    make the least assumptions that you can and establish everything else that
    you need explicitly. Note that in this case it would not even have costed
    at lot, as this code is just running once.

    I am not (!) trying to make people add inefficiences to their programs. It
    is just that when you are not completely sure that some improved solution
    works, you should do it the safe way.


Marc-Michael Brandis
Computer Systems Laboratory, ETH-Zentrum (Swiss Federal Institute of Technology)
CH-8092 Zurich, Switzerland
email: brandis@inf.ethz.ch