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