jaynec@homxc.UUCP (J.KING) (05/04/88)
In article <539@siemens.UUCP>, jrv@siemens.UUCP (James R Vallino) writes: > In article <2045@optilink.UUCP> elliott@optilink.UUCP (Paul Elliott x225) writes: > >I am doing some TSR stuff using Microsoft C 5.0, and would like to > >get access to the SS and SP registers (to set up a local stack). > >TurboC has psuedo-variables for all the registers, and it is pretty > >simple to read and write to these and do what I want (in TutboC). > > I had the same wish and could not find a way to set up a local stack short > of some assembly code. I punted and took the risk of using whatever stack > is active when the TSR is entered. So far that has worked but I would be > wary of not putting in the stack swap for a general use TSR. > That's a bad risk in my experience. I have successfully managed stack swapping -- you are right, assembler is the only way. At the end of this I will include the source code, NO GUARENTEES -- this works for me, but it's by no means foolproof. You'd better swap stacks or you might get in real deep stuff. You should realize that if you don't swap stacks, you should compile so that the code knows that DS<>SS when its compiling your routine. This is accomplished with a -Aw (FLAME ON: WHY DOES MICROSOFT INSIST ON CASE SENSITIVE COMMAND LINE OPTIONS. FLAME OFF -- I feel better ), as in "cl -Od -AL -Aw foo.c". Without this, I had several bizarre problems like code hanging on the statement "x = y". Even with this option, however, you must realize that almost all of the C runtime libraries are compiled to work only if DS=SS (I had originally written iff but MS bugs made me change the wording), and you can't really be sure whether or not the routine you want will cause a bizarre hangup. For example, ctime() uses the stack partially -- in my example, I simply printed the current time, and it came out as partially correct, and partially greek letters -- the stack had been used for some of the date stamp instead of the data segment (that sort of stuff makes me really nervous). Of course, you can simply ignore all of the C runtime routines -- in a TSR you may have to anyway because of re-entrency (sp?) problems, but if you have to give up the runtime stuff you might as well use assembler anyway. (Spoken like a true ASM hacker). Finally, even after you swap stacks, you will (as I did) run into a real pain -- stack overflow messages that are generated because of the stack swapping and not by any real stack overflows. My response to this was to turn off all stack checking (compile with -Ox, equivalent to living dangerously). BUT SURPRISE, runtime library routines check the stack anyway and kick you out. At this point, I called MS and (HUZZAHS ON ------ ============================================================= MICROSOFT PRODUCT SUPPORT ANSWERED MY QUESTION!!! ============================================================= HUZZAHS OFF -- its the first time they've really answered a question successfully and I am grateful). They referred my to the assembler stack checking routine (which I'd forgotten was supplied on the UTILITIES disk), which allows me to turn optimization back off, and get around the error checks. Here are the two routines for stack swapping -- These assume large model compiles and provide a stack that is accessible only to the assembler routine. The stack size is provided by the user. Call StackADJ() to swap stacks, and StackRES() to restore original stack. I call these from within my C interrupt handler routine (which has already changed DS to the "correct" value). Redirect any flames about these routines to /dev/null. James H. King AT&T Bell Laboratories HO 3K302 homxc!jaynec 201 949 8908 ; Static Name Aliases ; ; extrn _CurrentSS:word ; extrn _CurrentSP:word extrn STKHQQ:word ; stack bottom STACK_TEXT SEGMENT WORD PUBLIC 'CODE' STACK_TEXT ENDS _DATA SEGMENT WORD PUBLIC 'DATA' LocalStack db 4024d dup ("stack ") StackTop db 0 Orig_SS dw 0 Orig_SP dw 0 Orig_BP dw 0 Orig_DI dw 0 Orig_SI dw 0 OrigSTKHQQ dw 0 _DATA ENDS CONST SEGMENT WORD PUBLIC 'CONST' CONST ENDS _BSS SEGMENT WORD PUBLIC 'BSS' _BSS ENDS DGROUP GROUP CONST, _BSS, _DATA ASSUME CS: STACK_TEXT, DS: DGROUP, SS: DGROUP STACK_TEXT SEGMENT ASSUME CS: STACK_TEXT PUBLIC _StackADJ PUBLIC _StackRES _StackADJ PROC FAR mov ax,ss mov Orig_SS,ax mov ax,sp mov Orig_SP,ax mov ax,bp mov Orig_BP,ax mov ax,di mov Orig_DI,ax mov ax,si mov Orig_SI,ax mov bp,sp mov ax,STKHQQ mov OrigSTKHQQ,ax mov cx,ss:[bp] ;load return address offset mov dx,ss:[bp+2] ;load return address segment mov ax,ds mov ss,ax mov ax,offset LocalStack+4024d ;load top of local stack mov sp,ax ;reset stack pointer mov ax,offset LocalStack mov [STKHQQ],ax push dx ;push return segment to new stack push cx ;push return offset to new stack mov bp,sp ret _StackADJ ENDP _StackRES PROC FAR mov bp,sp mov cx,ss:[bp] ;load return address offset mov dx,ss:[bp+2] ;load return address segment mov ax,Orig_SS mov ss,ax mov ax,Orig_SP mov sp,ax mov ax,Orig_BP mov bp,ax mov ax,Orig_SI mov si,ax mov ax,Orig_DI mov di,ax mov ax,OrigSTKHQQ mov STKHQQ,ax push dx ;push return segment to new stack push cx ;push return offset to new stack ret _StackRES ENDP STACK_TEXT ENDS END