1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 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 unconditionally.
* 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 established 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
|