diff options
author | Ken Hirsch <kenhirsch@ftml.net> | 2006-01-12 08:26:16 -0500 |
---|---|---|
committer | H.Merijn Brand <h.m.brand@xs4all.nl> | 2006-01-12 19:52:01 +0000 |
commit | f382e41b709944009ae4d545ba1b94e4ddc6a66e (patch) | |
tree | 9c07b2e33d89bbf664dc11b20215e0d1ce3cfc5d /mpeix/mpeix_setjmp.c | |
parent | a11019f8bfc1b4438fdb32560361d443c701e293 (diff) | |
download | perl-f382e41b709944009ae4d545ba1b94e4ddc6a66e.tar.gz |
Re: Today's compiling adventure
Message-ID: <43C69F48.7090600@ftml.net>
p4raw-id: //depot/perl@26807
Diffstat (limited to 'mpeix/mpeix_setjmp.c')
-rw-r--r-- | mpeix/mpeix_setjmp.c | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/mpeix/mpeix_setjmp.c b/mpeix/mpeix_setjmp.c new file mode 100644 index 0000000000..955fe03d15 --- /dev/null +++ b/mpeix/mpeix_setjmp.c @@ -0,0 +1,355 @@ +/* Workaround for CR JAGab60546 setjmp/longjmp and + JAGad55982 sigsetjmp/siglongjmp from shared libraries. */ + +/* + * tabstop=4 + * + * _setjmp/setjmp/sigsetjmp and + *_longjmp/longjmp/siglongjmp. + * + * Written by Mark Klein, 10 October, 2000 + * Updated for gcc 3.x 6 October, 2005 + * + * These routines are GCC specific and MUST BE COMPILED + * WITH -O2 + * + * The existing setjmp/longjmp code in both libc.a and XL.PUB.SYS + * are not SR4 aware and cause problems when working with shared + * libraries (XLs), especially when executing a longjmp between + * XLs. This code preserves SR4 and will successfully handle + * a cross space longjmp. However, the setjmp code must be + * bound into each XL from which it will be called as well as + * being bound into the main program. + */ + +/* + * The following macro takes the contents of the jmpbuf and + * restores the registers from them. There is other code + * elsewhere that ensures that __jmpbuf is %r26 at this + * point in time. If it becomes some other register, that + * register must be the last restored. At the end will + * be a branch external that will cause a cross space + * return if needed. + */ +#define RESTORE_REGS_AND_RETURN(__jmpbuf, __retval) \ +({ \ + __asm__ __volatile__ ( \ + " ldw 0(%%sr0, %0), %%rp\n" \ + "\t ldw 4(%%sr0, %0), %%sp\n" \ + "\t ldw 16(%%sr0, %0), %%r3\n" \ + "\t ldw 20(%%sr0, %0), %%r4\n" \ + "\t ldw 24(%%sr0, %0), %%r5\n" \ + "\t ldw 28(%%sr0, %0), %%r6\n" \ + "\t ldw 32(%%sr0, %0), %%r7\n" \ + "\t ldw 36(%%sr0, %0), %%r8\n" \ + "\t ldw 40(%%sr0, %0), %%r9\n" \ + "\t ldw 44(%%sr0, %0), %%r10\n" \ + "\t ldw 48(%%sr0, %0), %%r11\n" \ + "\t ldw 52(%%sr0, %0), %%r12\n" \ + "\t ldw 56(%%sr0, %0), %%r13\n" \ + "\t ldw 60(%%sr0, %0), %%r14\n" \ + "\t ldw 64(%%sr0, %0), %%r15\n" \ + "\t ldw 68(%%sr0, %0), %%r16\n" \ + "\t ldw 72(%%sr0, %0), %%r17\n" \ + "\t ldw 76(%%sr0, %0), %%r18\n" \ + "\t ldw 80(%%sr0, %0), %%r19\n" \ + "\t ldw 84(%%sr0, %0), %%r20\n" \ + "\t ldw 88(%%sr0, %0), %%r21\n" \ + "\t ldw 92(%%sr0, %0), %%r22\n" \ + "\t ldw 96(%%sr0, %0), %%r23\n" \ + "\t ldw 100(%%sr0, %0), %%r24\n" \ + "\t ldw 104(%%sr0, %0), %%r25\n" \ + "\t ldw 112(%%sr0, %0), %%r27\n" \ + "\t ldw 116(%%sr0, %0), %%r1\n" \ + "\t mtsp %%r1, %%sr3\n" \ + "\t ldw 120(%%sr0, %0), %%r1\n" \ + "\t mtsp %%r1, %%sr1\n" \ + "\t or,<> %%r0, %1, %%r0\n" \ + "\t ldi 1, %%r28\n" \ + "\t ldw 108(%%sr0, %0), %%r26\n" \ + "\t be 0(%%sr1, %%rp)\n" \ + "\t mtsp %%r1, %%sr4\n" \ + : \ + : "r" (__jmpbuf), \ + "r" (__retval)); \ +}) + +/* + * The following macro extracts the signal mask + * from __jmpbuf from the 3rd and 4th words and + * if non-zero, calls sigprocmask with that value + * to set the signal mask. This macro is usually + * invoked before the registers are restored in + * the longjmp routines and it can clobber things + * without needing to spill them as a result. + * A quick frame is built before making the + * call and cut back just afterwards. + * The ldi 2, %r26 is actually SIG_SETMASK from + * /usr/include/signal.h. + */ +#define RESTORE_SIGNAL_MASK(__jmpbuf) \ +({ \ + __asm__ __volatile__ ( \ + " ldw 8(%0), %%r26\n" \ + "\t comibt,=,n 0,%%r26,.+36\n" \ + "\t ldo 64(%%sp), %%sp\n" \ + "\t stw %0, -28(%%sp)\n" \ + "\t ldi 0, %%r24\n" \ + "\t ldo 8(%0), %%r25\n" \ + "\t .import sigprocmask,code\n" \ + "\t bl sigprocmask,%%rp\n" \ + "\t ldi 2, %%r26\n" \ + "\t ldw -28(%%sr0, %%sp), %0\n" \ + "\t ldo -64(%%sp), %%sp\n" \ + : \ + : "r" (__jmpbuf)); \ +}) + +/* + * This macro saves the current contents of the + * registers to __jmpbuf. Note that __jmpbuf is + * guaranteed elsewhere to be in %r26. We do not + * want it spilled, nor do we want a new frame + * built. + */ +#define SAVE_REGS(__jmpbuf) \ +({ \ + __asm__ __volatile__ ( \ + " stw %%rp, 0(%%sr0, %0)\n" \ + "\t stw %%sp, 4(%%sr0, %0)\n" \ + "\t stw %%r0, 8(%%sr0, %0)\n" \ + "\t stw %%r3, 16(%%sr0, %0)\n" \ + "\t stw %%r4, 20(%%sr0, %0)\n" \ + "\t stw %%r5, 24(%%sr0, %0)\n" \ + "\t stw %%r6, 28(%%sr0, %0)\n" \ + "\t stw %%r7, 32(%%sr0, %0)\n" \ + "\t stw %%r8, 36(%%sr0, %0)\n" \ + "\t stw %%r9, 40(%%sr0, %0)\n" \ + "\t stw %%r10, 44(%%sr0, %0)\n" \ + "\t stw %%r11, 48(%%sr0, %0)\n" \ + "\t stw %%r12, 52(%%sr0, %0)\n" \ + "\t stw %%r13, 56(%%sr0, %0)\n" \ + "\t stw %%r14, 60(%%sr0, %0)\n" \ + "\t stw %%r15, 64(%%sr0, %0)\n" \ + "\t stw %%r16, 68(%%sr0, %0)\n" \ + "\t stw %%r17, 72(%%sr0, %0)\n" \ + "\t stw %%r18, 76(%%sr0, %0)\n" \ + "\t stw %%r19, 80(%%sr0, %0)\n" \ + "\t stw %%r20, 84(%%sr0, %0)\n" \ + "\t stw %%r21, 88(%%sr0, %0)\n" \ + "\t stw %%r22, 92(%%sr0, %0)\n" \ + "\t stw %%r23, 96(%%sr0, %0)\n" \ + "\t stw %%r24, 100(%%sr0, %0)\n" \ + "\t stw %%r25, 104(%%sr0, %0)\n" \ + "\t stw %%r26, 108(%%sr0, %0)\n" \ + "\t stw %%r27, 112(%%sr0, %0)\n" \ + "\t mfsp %%sr3, %%r1\n" \ + "\t stw %%r1, 116(%%sr0, %0)\n" \ + "\t mfsp %%sr4, %%r1\n" \ + "\t stw %%r1, 120(%%sr0, %0)\n" \ + : \ + : "r" (__jmpbuf)); \ +}) + +/* + * This macro will save the signal mask to the + * __jmpbuf if __savemask is non-zero. By this + * point in time, the other resisters have been + * saved into the __jmpbuf. + * The ldi 0, %r26 is actually SIG_BLOCK from + * /usr/include/signal.h. Since the block is + * an OR of the bits, this does not change the + * mask, but returns it into the double word at + * the address in %r24. + */ +#define SAVE_SIGNAL_MASK(__jmpbuf,__savemask) \ +({ \ + __asm__ __volatile__ ( \ + " comibt,=,n 0,%1,.+36\n" \ + "\t stw %%rp, -20(%%sr0, %%sp)\n" \ + "\t ldo 64(%%sp), %%sp\n" \ + "\t ldo 8(%0), %%r24\n" \ + "\t ldi 0, %%r25\n" \ + "\t .import sigprocmask,code\n" \ + "\t bl sigprocmask,%%rp\n" \ + "\t ldi 0, %%r26\n" \ + "\t ldo -64(%%sp), %%sp\n" \ + "\t ldw -20(%%sr0, %%sp), %%rp\n" \ + : \ + : "r" (__jmpbuf), \ + "r" (__savemask)); \ +}) + +/* + * Construct a jump buffer and unconditionally save + * the signal mask. Return a 0 unconditinoally. + * Care is taken here and in the macros to assume + * the __jumpbuf is in %r26 and that the return + * value will be in %r28. It is done this way to + * prevent a frame from being built and any registers + * from being spilled. + */ +int setjmp(register void *jmpbuf) +{ + register int __jmpbuf asm ("%r26"); + + SAVE_REGS(__jmpbuf); + SAVE_SIGNAL_MASK(__jmpbuf, 1); + return 0; +} + +/* + * Construct a jump buffer but do not save the + * signal mask. + */ +int _setjmp(register void *jmpbuf) +{ + register int __jmpbuf asm ("%r26"); + + SAVE_REGS(__jmpbuf); + return 0; +} + +/* + * Construct a jump buffer and conditionally save + * the signal mask. The mask is saved if the + * savemask parameter is non-zero. + */ +int sigsetjmp(register void *jmpbuf, register int savemask) +{ + register int __jmpbuf asm ("%r26"); + register int __savemask asm ("%r25"); + + SAVE_REGS(__jmpbuf); + SAVE_SIGNAL_MASK(__jmpbuf, __savemask); + return 0; +} + +/* + * Return to the location established in the jmpbuf, + * and place the value in i2 in %r28. Registers + * %r4 and %r5 are co-opted to save the address and + * value of jmpbuf and the return value. The signal + * mask is re-established if needed, then the + * address of jmpbuf and value of retval are placed + * into %r26 and %r28 correspondingly. This routine + * will never return to its caller and the stack + * will be cut back to whatever exists in the jmpbuf. + */ +void longjmp(register void *jmpbuf, register int i2) +{ + register int __jmpbuf asm ("%r26"); + register int __retval asm ("%r28"); + + __asm__ __volatile__ ( + " copy %0, %%r4\n" + "\t copy %1, %%r5\n" + : + : "r" (jmpbuf), + "r" (i2)); + + RESTORE_SIGNAL_MASK (__jmpbuf); + + __asm__ __volatile__ ( + " copy %%r4, %0\n" + "\t copy %%r5, %1\n" + : "=r" (__jmpbuf), + "=r" (__retval)); + + RESTORE_REGS_AND_RETURN (__jmpbuf, __retval); +} + +/* + * Return to the location established in the jmpbuf, + * but do not restore the signal mask. + */ +void _longjmp(register void *jmpbuf, register int i2) +{ + register int __retval asm ("%r28"); + register int __jmpbuf asm ("%r26"); + + __jmpbuf = (int)jmpbuf; + __retval = i2; + + RESTORE_REGS_AND_RETURN (__jmpbuf, __retval); +} + +/* + * Return to the location establsihed in the jmpbuf, + * and conditionally re-establish the signal mask. + */ +void siglongjmp(register void *jmpbuf, register int i2) +{ + register int __jmpbuf asm ("%r26"); + register int __retval asm ("%r28"); + + __asm__ __volatile__ ( + " copy %0, %%r4\n" + "\t copy %1, %%r5\n" + : + : "r" (jmpbuf), + "r" (i2)); + + RESTORE_SIGNAL_MASK (__jmpbuf); + + __asm__ __volatile__ ( + " copy %%r4, %0\n" + "\t copy %%r5, %1\n" + : "=r" (__jmpbuf), + "=r" (__retval)); + + RESTORE_REGS_AND_RETURN (__jmpbuf, __retval); +} + +#ifdef TEST +int buf1[50]; +int buf2[50]; + +foo() { + printf("In routine foo(). Doing Longjmp.\n"); + longjmp(buf1, 123); + printf("This is in foo after the longjmp() call. Should not reach here.\n"); +} + +bar(int ret) { + printf("In routine bar(%d). Doing siglongjmp.\n",ret); + siglongjmp(buf2, ret); + printf("This is in bar after the siglongjmp() call. Should not reach here.\n"); +} + +main() { + int i; + if ((i = setjmp(buf1))) + { + printf("This is the return from the longjmp. i: %d\n",i); + } + else + { + printf("Jump buffer established, i: %d. Calling foo()\n",i); + foo(); + printf("This is in main after the foo() call. Should not reach here.\n "); + } + + if ((i = sigsetjmp(buf2,0))) + { + printf("This is the return from the longjmp. i: %d\n",i); + } + else + { + printf("Jump buffer established, i: %d. Calling bar(456)\n",i); + bar(456); + printf("This is in main after the bar(456) call. Should not reach here.\n"); + } + + if ((i = sigsetjmp(buf2,1))) + { + printf("This is the return from the longjmp. i: %d\n",i); + } + else + { + printf("Jump buffer established, i: %d. Calling bar(789)\n",i); + bar(789); + printf("This is in main after the bar(789) call. Should not reach here.\n"); + } +} +#endif |