This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: Today's compiling adventure
[perl5.git] / mpeix / mpeix_setjmp.c
1 /* Workaround for CR JAGab60546 setjmp/longjmp and
2    JAGad55982 sigsetjmp/siglongjmp from shared libraries. */
3
4 /*
5   * tabstop=4
6   *
7   * _setjmp/setjmp/sigsetjmp and
8   *_longjmp/longjmp/siglongjmp.
9   *
10   * Written by Mark Klein, 10 October, 2000
11   * Updated for gcc 3.x 6 October, 2005
12   *
13   * These routines are GCC specific and MUST BE COMPILED
14   * WITH -O2
15   *
16   * The existing setjmp/longjmp code in both libc.a and XL.PUB.SYS
17   * are not SR4 aware and cause problems when working with shared
18   * libraries (XLs), especially when executing a longjmp between
19   * XLs. This code preserves SR4 and will successfully handle
20   * a cross space longjmp. However, the setjmp code must be
21   * bound into each XL from which it will be called as well as
22   * being bound into the main program.
23   */
24
25 /*
26   * The following macro takes the contents of the jmpbuf and
27   * restores the registers from them. There is other code
28   * elsewhere that ensures that __jmpbuf is %r26 at this
29   * point in time. If it becomes some other register, that
30   * register must be the last restored. At the end will
31   * be a branch external that will cause a cross space
32   * return if needed.
33   */
34 #define RESTORE_REGS_AND_RETURN(__jmpbuf, __retval)                  \
35 ({                                                                   \
36          __asm__ __volatile__ (                                      \
37              "   ldw    0(%%sr0, %0), %%rp\n"                        \
38              "\t   ldw    4(%%sr0, %0), %%sp\n"                      \
39              "\t   ldw   16(%%sr0, %0), %%r3\n"                      \
40              "\t   ldw   20(%%sr0, %0), %%r4\n"                      \
41              "\t   ldw   24(%%sr0, %0), %%r5\n"                      \
42              "\t   ldw   28(%%sr0, %0), %%r6\n"                      \
43              "\t   ldw   32(%%sr0, %0), %%r7\n"                      \
44              "\t   ldw   36(%%sr0, %0), %%r8\n"                      \
45              "\t   ldw   40(%%sr0, %0), %%r9\n"                      \
46              "\t   ldw   44(%%sr0, %0), %%r10\n"                     \
47              "\t   ldw   48(%%sr0, %0), %%r11\n"                     \
48              "\t   ldw   52(%%sr0, %0), %%r12\n"                     \
49              "\t   ldw   56(%%sr0, %0), %%r13\n"                     \
50              "\t   ldw   60(%%sr0, %0), %%r14\n"                     \
51              "\t   ldw   64(%%sr0, %0), %%r15\n"                     \
52              "\t   ldw   68(%%sr0, %0), %%r16\n"                     \
53              "\t   ldw   72(%%sr0, %0), %%r17\n"                     \
54              "\t   ldw   76(%%sr0, %0), %%r18\n"                     \
55              "\t   ldw   80(%%sr0, %0), %%r19\n"                     \
56              "\t   ldw   84(%%sr0, %0), %%r20\n"                     \
57              "\t   ldw   88(%%sr0, %0), %%r21\n"                     \
58              "\t   ldw   92(%%sr0, %0), %%r22\n"                     \
59              "\t   ldw   96(%%sr0, %0), %%r23\n"                     \
60              "\t   ldw  100(%%sr0, %0), %%r24\n"                     \
61              "\t   ldw  104(%%sr0, %0), %%r25\n"                     \
62              "\t   ldw  112(%%sr0, %0), %%r27\n"                     \
63              "\t   ldw  116(%%sr0, %0), %%r1\n"                      \
64              "\t   mtsp %%r1, %%sr3\n"                               \
65              "\t   ldw  120(%%sr0, %0), %%r1\n"                      \
66              "\t   mtsp %%r1, %%sr1\n"                               \
67              "\t   or,<>   %%r0, %1, %%r0\n"                         \
68              "\t     ldi 1, %%r28\n"                                 \
69              "\t   ldw  108(%%sr0, %0), %%r26\n"                     \
70              "\t   be       0(%%sr1, %%rp)\n"                        \
71              "\t   mtsp %%r1, %%sr4\n"                               \
72                  : \
73                  : "r" (__jmpbuf),                                   \
74                    "r" (__retval));                                  \
75 })
76
77 /*
78   * The following macro extracts the signal mask
79   * from  __jmpbuf from the 3rd and 4th words and
80   * if non-zero, calls sigprocmask with that value
81   * to set the signal mask. This macro is usually
82   * invoked before the registers are restored in
83   * the longjmp routines and it can clobber things
84   * without needing to spill them as a result.
85   * A quick frame is built before making the
86   * call and cut back just afterwards.
87   * The ldi 2, %r26 is actually SIG_SETMASK from
88   * /usr/include/signal.h.
89   */
90 #define RESTORE_SIGNAL_MASK(__jmpbuf)                                \
91 ({                                                                   \
92    __asm__ __volatile__ (                                            \
93               "  ldw 8(%0), %%r26\n"                                 \
94               "\t  comibt,=,n 0,%%r26,.+36\n"                        \
95               "\t    ldo 64(%%sp), %%sp\n"                           \
96               "\t    stw %0, -28(%%sp)\n"                            \
97               "\t    ldi 0, %%r24\n"                                 \
98               "\t    ldo 8(%0), %%r25\n"                             \
99               "\t    .import sigprocmask,code\n"                     \
100               "\t    bl sigprocmask,%%rp\n"                          \
101               "\t    ldi 2, %%r26\n"                                 \
102               "\t    ldw -28(%%sr0, %%sp), %0\n"                     \
103               "\t    ldo -64(%%sp), %%sp\n"                          \
104                      :                                               \
105                      : "r" (__jmpbuf));                              \
106 })
107
108 /*
109   * This macro saves the current contents of the
110   * registers to __jmpbuf. Note that __jmpbuf is
111   * guaranteed elsewhere to be in %r26. We do not
112   * want it spilled, nor do we want a new frame
113   * built.
114   */
115 #define SAVE_REGS(__jmpbuf)                                          \
116 ({                                                                   \
117    __asm__ __volatile__ (                                            \
118               "  stw %%rp,     0(%%sr0, %0)\n"                       \
119               "\t  stw %%sp,     4(%%sr0, %0)\n"                     \
120               "\t  stw %%r0,     8(%%sr0, %0)\n"                     \
121               "\t  stw %%r3,    16(%%sr0, %0)\n"                     \
122               "\t  stw %%r4,    20(%%sr0, %0)\n"                     \
123               "\t  stw %%r5,    24(%%sr0, %0)\n"                     \
124               "\t  stw %%r6,    28(%%sr0, %0)\n"                     \
125               "\t  stw %%r7,    32(%%sr0, %0)\n"                     \
126               "\t  stw %%r8,    36(%%sr0, %0)\n"                     \
127               "\t  stw %%r9,    40(%%sr0, %0)\n"                     \
128               "\t  stw %%r10,   44(%%sr0, %0)\n"                     \
129               "\t  stw %%r11,   48(%%sr0, %0)\n"                     \
130               "\t  stw %%r12,   52(%%sr0, %0)\n"                     \
131               "\t  stw %%r13,   56(%%sr0, %0)\n"                     \
132               "\t  stw %%r14,   60(%%sr0, %0)\n"                     \
133               "\t  stw %%r15,   64(%%sr0, %0)\n"                     \
134               "\t  stw %%r16,   68(%%sr0, %0)\n"                     \
135               "\t  stw %%r17,   72(%%sr0, %0)\n"                     \
136               "\t  stw %%r18,   76(%%sr0, %0)\n"                     \
137               "\t  stw %%r19,   80(%%sr0, %0)\n"                     \
138               "\t  stw %%r20,   84(%%sr0, %0)\n"                     \
139               "\t  stw %%r21,   88(%%sr0, %0)\n"                     \
140               "\t  stw %%r22,   92(%%sr0, %0)\n"                     \
141               "\t  stw %%r23,   96(%%sr0, %0)\n"                     \
142               "\t  stw %%r24,  100(%%sr0, %0)\n"                     \
143               "\t  stw %%r25,  104(%%sr0, %0)\n"                     \
144               "\t  stw %%r26,  108(%%sr0, %0)\n"                     \
145               "\t  stw %%r27,  112(%%sr0, %0)\n"                     \
146               "\t  mfsp %%sr3, %%r1\n"                               \
147               "\t  stw %%r1,   116(%%sr0, %0)\n"                     \
148               "\t  mfsp %%sr4, %%r1\n"                               \
149               "\t  stw %%r1,   120(%%sr0, %0)\n"                     \
150                    :                                                 \
151                    : "r" (__jmpbuf));                                \
152 })
153
154 /*
155   * This macro will save the signal mask to the
156   * __jmpbuf if __savemask is non-zero. By this
157   * point in time, the other resisters have been
158   * saved into the __jmpbuf.
159   * The ldi 0, %r26 is actually SIG_BLOCK from
160   * /usr/include/signal.h. Since the block is
161   * an OR of the bits, this does not change the
162   * mask, but returns it into the double word at
163   * the address in %r24.
164   */
165 #define SAVE_SIGNAL_MASK(__jmpbuf,__savemask)                        \
166 ({                                                                   \
167    __asm__ __volatile__ (                                            \
168               "  comibt,=,n 0,%1,.+36\n"                             \
169               "\t    stw %%rp, -20(%%sr0, %%sp)\n"                   \
170               "\t    ldo 64(%%sp), %%sp\n"                           \
171               "\t    ldo 8(%0), %%r24\n"                             \
172               "\t    ldi 0, %%r25\n"                                 \
173               "\t    .import sigprocmask,code\n"                     \
174               "\t    bl sigprocmask,%%rp\n"                          \
175               "\t    ldi 0, %%r26\n"                                 \
176               "\t    ldo -64(%%sp), %%sp\n"                          \
177               "\t    ldw -20(%%sr0, %%sp), %%rp\n"                   \
178                      :                                               \
179                      : "r" (__jmpbuf),                               \
180                        "r" (__savemask));                            \
181 })
182
183 /*
184   * Construct a jump buffer and unconditionally save
185   * the signal mask. Return a 0 unconditinoally.
186   * Care is taken here and in the macros to assume
187   * the __jumpbuf is in %r26 and that the return
188   * value will be in %r28. It is done this way to
189   * prevent a frame from being built and any registers
190   * from being spilled.
191   */
192 int setjmp(register void *jmpbuf)
193 {
194    register int __jmpbuf asm ("%r26");
195
196    SAVE_REGS(__jmpbuf);
197    SAVE_SIGNAL_MASK(__jmpbuf, 1);
198    return 0;
199 }
200
201 /*
202   * Construct a jump buffer but do not save the
203   * signal mask.
204   */
205 int _setjmp(register void *jmpbuf)
206 {
207    register int __jmpbuf asm ("%r26");
208
209    SAVE_REGS(__jmpbuf);
210    return 0;
211 }
212
213 /*
214   * Construct a jump buffer and conditionally save
215   * the signal mask. The mask is saved if the
216   * savemask parameter is non-zero.
217   */
218 int sigsetjmp(register void *jmpbuf, register int savemask)
219 {
220    register int __jmpbuf   asm ("%r26");
221    register int __savemask asm ("%r25");
222
223    SAVE_REGS(__jmpbuf);
224    SAVE_SIGNAL_MASK(__jmpbuf, __savemask);
225    return 0;
226 }
227
228 /*
229   * Return to the location established in the jmpbuf,
230   * and place the value in i2 in %r28. Registers
231   * %r4 and %r5 are co-opted to save the address and
232   * value of jmpbuf and the return value. The signal
233   * mask is re-established if needed, then the
234   * address of jmpbuf and value of retval are placed
235   * into %r26 and %r28 correspondingly. This routine
236   * will never return to its caller and the stack
237   * will be cut back to whatever exists in the jmpbuf.
238   */
239 void longjmp(register void *jmpbuf, register int i2)
240 {
241    register int __jmpbuf        asm ("%r26");
242    register int __retval        asm ("%r28");
243
244    __asm__ __volatile__ (
245               "  copy %0, %%r4\n"
246               "\t  copy %1, %%r5\n"
247                      :
248                      : "r" (jmpbuf),
249                        "r" (i2));
250
251    RESTORE_SIGNAL_MASK (__jmpbuf);
252
253    __asm__ __volatile__ (
254               "  copy %%r4, %0\n"
255               "\t  copy %%r5, %1\n"
256                      : "=r" (__jmpbuf),
257                        "=r" (__retval));
258
259    RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
260 }
261
262 /*
263   * Return to the location established in the jmpbuf,
264   * but do not restore the signal mask.
265   */
266 void _longjmp(register void *jmpbuf, register int i2)
267 {
268    register int __retval         asm ("%r28");
269    register int __jmpbuf         asm ("%r26");
270
271    __jmpbuf = (int)jmpbuf;
272    __retval = i2;
273
274    RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
275 }
276
277 /*
278   * Return to the location establsihed in the jmpbuf,
279   * and conditionally re-establish the signal mask.
280   */
281 void siglongjmp(register void *jmpbuf, register int i2)
282 {
283    register int __jmpbuf        asm ("%r26");
284    register int __retval        asm ("%r28");
285
286    __asm__ __volatile__ (
287               "  copy %0, %%r4\n"
288               "\t  copy %1, %%r5\n"
289                      :
290                      : "r" (jmpbuf),
291                        "r" (i2));
292
293    RESTORE_SIGNAL_MASK (__jmpbuf);
294
295    __asm__ __volatile__ (
296               "  copy %%r4, %0\n"
297               "\t  copy %%r5, %1\n"
298                      : "=r" (__jmpbuf),
299                        "=r" (__retval));
300
301    RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
302 }
303
304 #ifdef TEST
305 int buf1[50];
306 int buf2[50];
307
308 foo() {
309    printf("In routine foo(). Doing Longjmp.\n");
310    longjmp(buf1, 123);
311    printf("This is in foo after the longjmp() call. Should not reach here.\n");
312 }
313
314 bar(int ret) {
315    printf("In routine bar(%d). Doing siglongjmp.\n",ret);
316    siglongjmp(buf2, ret);
317    printf("This is in bar after the siglongjmp() call. Should not reach here.\n");
318 }
319
320 main() {
321    int i;
322    if ((i = setjmp(buf1)))
323      {
324            printf("This is the return from the longjmp. i: %d\n",i);
325          }
326    else
327      {
328            printf("Jump buffer established, i: %d. Calling foo()\n",i);
329            foo();
330            printf("This is in main after the foo() call. Should not reach here.\n ");
331          }
332
333    if ((i = sigsetjmp(buf2,0)))
334      {
335            printf("This is the return from the longjmp. i: %d\n",i);
336          }
337    else
338      {
339            printf("Jump buffer established, i: %d. Calling bar(456)\n",i);
340            bar(456);
341            printf("This is in main after the bar(456) call. Should not reach here.\n");
342          }
343
344    if ((i = sigsetjmp(buf2,1)))
345      {
346            printf("This is the return from the longjmp. i: %d\n",i);
347          }
348    else
349      {
350            printf("Jump buffer established, i: %d. Calling bar(789)\n",i);
351            bar(789);
352            printf("This is in main after the bar(789) call. Should not reach here.\n");
353          }
354 }
355 #endif