Article View: comp.os.msdos.programmer
Article #5851Chaining interrupt handlers in Turbo C
From: Dave Andrews
Date: Wed, 17 Apr 1991 21:40
Date: Wed, 17 Apr 1991 21:40
80 lines
4447 bytes
4447 bytes
/*
* A week or so ago, someone asked:
* "how can I chain to the next interrupt handler in Turbo C?"
*
* Shortly after the post appeared, I needed the same function.
* I see from _Undocumented DOS_ that MSC has the "_chain_intr"
* builtin that does what you want. Unfortunately, TC doesn't
* have an equivalent function (see _Undocumented DOS_ page 379).
*
* Here is my solution to the problem. It is not particularly
* elegant, and is HIGHLY dependent on the code TC++ 1.0 generates
* for INTERRUPT function epilogs. I've only tested it on a
* '286 machine in the large model. YMMV and all that.
*
* Just before exit, the stack contains saved registers, CS/IP
* and flags. I shift the stack, duplicating the CS/IP/flags
* (6 bytes) and modify the topmost CS/IP to point to the previous
* interrupt handler. Then I let TC's generated exit code restore
* registers and IRET to the previous handler. When the previous
* handler does its own IRET, it returns control to my original
* caller.
*
* Note that the chain_intr macro destroys a number of registers
* rather indiscriminately. Use chain_intr() just before your
* INTERRUPT function executes a return. The stack should be
* the same as it was on entry, i.e. don't use chain_intr()
* inside a subordinate function call.
*
* Hope this helps.
*
* - David Andrews bilver!dandrews
*/
#include <dos.h>
#define chain_intr(old) \
asm { \
push ds; /* Need DS for access to "old" pointer */ \
mov si,sp; /* -> current top of stack */ \
sub sp,6; /* -> new top of stack after shift */ \
mov di,ss; /* Setup DS, ES for move */ \
mov ds,di; /* DS:SI is source of move */ \
mov es,di; /* */ \
mov di,sp; /* ES:DI is destination of move */ \
mov cx,12; /* Moving 24 bytes (12 words) */ \
rep movsw; /* Shift stack 6 bytes */ \
pop ds; /* Restore DS */ \
cli ; /* Protect stack */ \
add sp,22; /* Zap IRET address to prior handler */ \
push DWORD PTR _##old; /* " */ \
sub sp,18; /* " */ \
sti ; /* Unprotect stack */ \
}
void interrupt (*oldfunc) (); /* Object of getvect(), setvect() */
void interrupt first () { /* Sample handler - installed first */
puts("First");
}
void interrupt second () { /* Sample handler - installed second */
puts("Second");
chain_intr (oldfunc); /* Example use of "chain_intr" macro */
}
void main() {
setvect(255, first); /* Install "first" as INT 255 handler */
oldfunc = getvect(255); /* getvect() its address */
setvect(255, second); /* Install the second INT 255 handler */
geninterrupt(255); /* Call the second INT 255 handler. */
/* It will execute and pass control to */
/* the previous handler (whose address */
/* is stored in "oldfunc"). Expected */
/* output is: */
/* Second */
/* First */
};
Technical Details
Message-ID:
<1991Apr17.214023.22334@bilver.uucp>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!wuarchive!emory!tridom!atssc!fang!tarpit!bilver!dandrewsShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!wuarchive!emory!tridom!atssc!fang!tarpit!bilver!dandrews From: dandrews@bilver.uucp (Dave Andrews) Newsgroups: comp.os.msdos.programmer Subject: Chaining interrupt handlers in Turbo C Keywords: TC TURBOC interrupt _chain_intr Message-ID: <1991Apr17.214023.22334@bilver.uucp> Date: 17 Apr 91 21:40:23 GMT Organization: W. J. Vermillion - Winter Park, FL Lines: 80