This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #70802] -i'*' refuses to work
[perl5.git] / mpeix / mpeix_setjmp.c
CommitLineData
f382e41b
KH
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 */
192int 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 */
205int _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 */
218int 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 */
239void 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 */
266void _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 */
281void 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
305int buf1[50];
306int buf2[50];
307
308foo() {
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
314bar(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
320main() {
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