[comp.sys.ibm.pc.programmer] Notes about Borland C++ interrupt keyword

jwbirdsa@amc.com (James Birdsall) (05/21/91)

   Anyone writing interrupt handlers using TC++'s "interrupt" keyword
should be aware that DS is not preserved into the function. DS is preserved
through the function; the value of DS after the interrupt is the same as
before. However, the value of DS while the function is executing is not the
same as the value when it was called. The entry code pushes all the
registers on the stack and then reloads DS with the value for the program's
near data segment.

   This doesn't matter for most interrupt handlers, but if you're trying to
revector an interrupt that uses DS as a parameter (for example, the DOS
interrupt (0x21)), then it becomes a major obstacle.

   This behavior has been observed with Borland C++ 2.0. Presumably it is
the same with TC++ 1.0, and probably plain TC. It is not mentioned as such
in the documentation, although if you read it carefully it is implied.
Anyway, having spent an hour or two tracing the errors caused by this
behavior, I thought it worth posting a public notice to save other people
the trouble.

-- 
James W. Birdsall   WORK: jwbirdsa@amc.com   {uunet,uw-coco}!amc-gw!jwbirdsa
HOME: {uunet,uw-coco}!amc-gw!picarefy!jwbirdsa OTHER: 71261.1731@compuserve.com
================== Kitten: a small homicidal muffin on legs. ==================
=========== "For it is the doom of men that they forget." -- Merlin ===========

dmurdoch@watstat.waterloo.edu (Duncan Murdoch) (05/21/91)

In article <1991May20.171545.23591@amc.com> jwbirdsa@polaris.amc.com () writes:
>
>   Anyone writing interrupt handlers using TC++'s "interrupt" keyword
>should be aware that DS is not preserved into the function. DS is preserved
>through the function; the value of DS after the interrupt is the same as
>before. However, the value of DS while the function is executing is not the
>same as the value when it was called. The entry code pushes all the
>registers on the stack and then reloads DS with the value for the program's
>near data segment.
>
>   This doesn't matter for most interrupt handlers, but if you're trying to
>revector an interrupt that uses DS as a parameter (for example, the DOS
>interrupt (0x21)), then it becomes a major obstacle.
>
>   This behavior has been observed with Borland C++ 2.0. Presumably it is
>the same with TC++ 1.0, and probably plain TC. It is not mentioned as such
>in the documentation, although if you read it carefully it is implied.
>Anyway, having spent an hour or two tracing the errors caused by this
>behavior, I thought it worth posting a public notice to save other people
>the trouble.

I don't have any of the C flavours, but I'm surprised it's not documented 
there.  In TP, the prologue of an Interrupt procedure is explicitly given;
it says that DS is changed to the ISR's data segment.  If you want the old
DS, you just read the 3rd argument from the end; presumably in BC++ that
would be the 3rd from the beginning.

Duncan Murdoch
dmurdoch@watstat.waterloo.edu

ressler@CS.Cornell.EDU (Gene Ressler) (05/21/91)

In article <1991May20.230908.7178@maytag.waterloo.edu> dmurdoch@watstat.waterloo.edu (Duncan Murdoch) writes:
>In article <1991May20.171545.23591@amc.com> jwbirdsa@polaris.amc.com () writes:
>>
>>   Anyone writing interrupt handlers using TC++'s "interrupt" keyword
>>should be aware that DS is not preserved into the function. DS is preserved
>>through the function; the value of DS after the interrupt is the same as
>>before. However, the value of DS while the function is executing is not the
 ....

>I don't have any of the C flavours, but I'm surprised it's not documented 
>there.  In TP, the prologue of an Interrupt procedure is explicitly given;
 ....
>Duncan Murdoch
>dmurdoch@watstat.waterloo.edu

Both my TC++ manual (PG, pg 48) and my TC2.0 manual
(UG, pg 319) state that DS is set.  What else could
be done to provide access to static data?  This `behavior'
is, practically speaking, the only one possible.
(...that is, short of allowing statics in the code
segment (ugh).  I believe MSC provides this option.)
Chalk up one more for the joys of segmented
architectures. ;->

Gene

sorrow@oak.circa.ufl.edu (05/21/91)

In article <1991May20.230908.7178@maytag.waterloo.edu>, dmurdoch@watstat.waterloo.edu (Duncan Murdoch) writes:
|>In article <1991May20.171545.23591@amc.com> jwbirdsa@polaris.amc.com () writes:
|>>
|>>   Anyone writing interrupt handlers using TC++'s "interrupt" keyword
|>>should be aware that DS is not preserved into the function. DS is preserved
|>>through the function; the value of DS after the interrupt is the same as
|>>before. However, the value of DS while the function is executing is not the
|>>same as the value when it was called. The entry code pushes all the
|>>registers on the stack and then reloads DS with the value for the program's
|>>near data segment.
|>>
|>>   This doesn't matter for most interrupt handlers, but if you're trying to
|>>revector an interrupt that uses DS as a parameter (for example, the DOS
|>>interrupt (0x21)), then it becomes a major obstacle.
|>>
|>>   This behavior has been observed with Borland C++ 2.0. Presumably it is
|>>the same with TC++ 1.0, and probably plain TC. It is not mentioned as such
|>>in the documentation, although if you read it carefully it is implied.
|>>Anyway, having spent an hour or two tracing the errors caused by this
|>>behavior, I thought it worth posting a public notice to save other people
|>>the trouble.

Actually, I found out that I must be doing something terribly wrong.  When
I installed my own mouse interrupt handler, if the function was declared
as "void far interrupt" it would die.  "void far" worked just fine.  I just
don't USE the interrupt keyword.  The documentation is too skimpy on it
for me to be able to use it decently.

Brian

anicolao@watcgl.waterloo.edu (Alex Nicolaou) (05/22/91)

In article <00948EEF.C05FAA40@MAPLE.CIRCA.UFL.EDU> sorrow@oak.circa.ufl.edu writes:
>Actually, I found out that I must be doing something terribly wrong.  When
>I installed my own mouse interrupt handler, if the function was declared
>as "void far interrupt" it would die.  "void far" worked just fine.  

 ** Hmm. What do you mean you "installed my own mouse interrupt handler"? If
you mean via the services provided by the mouse driver (12h or 24h, I think)
which make the mouse driver call your function, then NO, you CANNOT use the
interrupt keyword; for a very simple reason: you aren't the interrupt handler,
you are being called by it, and you are supposed to be a routine. If you use
an interrupt function, the BC++ compiler will put an iret instruction in 
for you, and that will terminate the interrupt handling prematurely - your
Microsoft compatible driver will not have finished its work and your computer
will dissappear into limbo. Incidentally, if you are doing this and then 
accessing data, you'd better be sure that you're restoring DS yourself, since
the MS mouse driver won't do it for you - if you compile in Medium or Large
models this is an absolute must, in smaller models you ought to do it for 
painless changes later.

>I just
>don't USE the interrupt keyword.  The documentation is too skimpy on it
>for me to be able to use it decently.

 ** Interrupts are a pain, but that is not a function of the documentation.
Yes, I am another borland fan :-)

alex

grimlok@hubcap.clemson.edu (Mike Percy) (05/22/91)

sorrow@oak.circa.ufl.edu writes:

>Actually, I found out that I must be doing something terribly wrong.  When
>I installed my own mouse interrupt handler, if the function was declared
>as "void far interrupt" it would die.  "void far" worked just fine.  I just
>don't USE the interrupt keyword.  The documentation is too skimpy on it
>for me to be able to use it decently.
 
If you are talking about mouse function 12(?), theone that lets you have
the mouse driver call your function whenever certain mouse events
happen, then you are on the right track.  The "interrupt" handler you
give to the mouse is not of type void interrupt.  TurboC interrupt
functions push regs to the stack, do your stuff, pop the regs and --
IRET.  This is what screws you.  The driver does a simple far CALL to your
routine, expecting to have control come back to it with a far RET.  The
IRET is simply wrong here.  Declaring your mouse function to be void far
fixes this problem, but you still cannot access global/static data
except by sheer accident, as DS will likely not be pointing to your
DGROUP.  Declaring it as void huge does this trick.  But the mouse
driver also apparantly assumes a called-saved register scheme, while the
C compiler assumes a caller-saved scheme.  Your routine can trash
registers the mouse driver expected you to leave alone.  I use #pragma
savregs.  This guarantees that a huge function will not change the value
of any of the register when it is entered. I like the pragma rather than
declaring the function as _saveregs. _saveregs pushes all register and
pops them at the end.  This is costly in time/space.  The #pragma
saveregs costs more at compile time, but is much smaller/faster at
runtime.

In short, when installing a mouse handler (function 12), I declare it

#pragma saveregs
void huge handler(void)
{
  /* handler code */
} 
 
I spent a lot of time before getting this to work...


"I don't know about your brain, but mine is really...bossy."
Mike Percy                    grimlok@hubcap.clemson.edu
ISD, Clemson University       mspercy@clemson.BITNET
(803)656-3780                 mspercy@clemson.clemson.edu