Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!necntc!ames!ptsfa!ihnp4!alberta!ers!teletron!andrew From: andrew@teletron.UUCP (Andrew Scott) Newsgroups: comp.lang.c Subject: asm statements & the stack Message-ID: <110@teletron.UUCP> Date: Tue, 6-Oct-87 12:34:36 EDT Article-I.D.: teletron.110 Posted: Tue Oct 6 12:34:36 1987 Date-Received: Sat, 10-Oct-87 07:19:12 EDT Organization: TeleTronic Communications Ltd., Edmonton, Alta. Lines: 79 Many C compilers have one variation or another on the asm() "function". It allows one to insert inline assembly code in the middle of C code. I have been playing around with it a bit, and have a question. (The code I'm writing is targeted for a specific hardware system, so no flames for unportability please). What can I do in an asm() statement? The question arises because I was bitten by the compiler's code generation method. I was writing a function (for the 68000, if you don't recognize the assembly code) which must be non-interruptable. I have to disable all interrupts before executing the code, and re-enable them to the previous level when I'm done. My function looked something like: #define disable asm("mov.w %sr,-(%sp)"); asm("mov.w &0x2700,%sr") /* push current status register on stack, mask out interrupts */ #define restore asm("mov.w (%sp)+,%sr") /* restore status register from stack save location */ foo(a, b) int a, b; { int x, y; disable; bar(a, b); /* other stuff */ restore; } Was I correct in assuming the stack would be available to save the status reg.? The compiler I use (stock AT&T /bin/cc) does a wierd thing upon the call to foo. It allocates one more longword than necessary when creating foo's stack frame. The actual assembly output of the above function (obtained via cc -S) is: global foo foo: link %fp,&-12 /* allocate space for x, y & ? */ mov.w %sr,-(%sp) /* disable */ mov.w &0x2700,%sr /* "" */ mov.l 12(%fp),(%sp) /* note this is not a push of b */ mov.l 8(%fp),-(%sp) /* push a on stack */ jsr bar add.w &4,%sp /* clean up stack */ mov.w (%sp)+,%sr /* restore */ unlk %fp /* dealloocate stack frame */ rts Note that 12 bytes were allocated for local variables within the stack frame. Only 8 bytes (four each for x & y) are needed. Therefore, the stack pointer points to an unused longword location. Notice that the call to bar only pushes one argument. The argument b is simply moved to the unused location. This really messes up the intended action of disable, because the saved status register is overwritten. To conclude a long story, should I really be angry at whoever wrote the compiler for doing such a strange thing, or should I avoid asm statements altogether because I can't count on anything? The alternative is rather barfy: foo(a, b) int a, b; { int x, y; short ps; ps = disable(); /* actual function call */ bar(a, b); /* other stuff */ restore(ps); } Here, disable & restore are actual function calls to external assembly coded subroutines. There is much more overhead involved, and the functions which require the use of disable & restore are all quite time critical. Thanks for enduring a rather long posting and question. Andrew