/* BLURB lgpl Coda File System Release 5 Copyright (c) 1987-1999 Carnegie Mellon University Additional copyrights listed below This code is distributed "AS IS" without warranty of any kind under the terms of the GNU Library General Public Licence Version 2, as shown in the file LICENSE. The technical and financial contributors to Coda are listed in the file CREDITS. Additional copyrights #*/ /* IBM COPYRIGHT NOTICE Copyright (C) 1986 International Business Machines Corporation All Rights Reserved This file contains some code identical to or derived from the 1986 version of the Andrew File System ("AFS"), which is owned by the IBM Corporation. This code is provided "AS IS" and IBM does not warrant that it is free of infringement of any intellectual rights of any third party. IBM disclaims liability of any kind for any damages whatsoever resulting directly or indirectly from use of this software or of any derivative work. Carnegie Mellon University has obtained permission to modify, distribute and sublicense this code, which is based on Version 2 of AFS and does not contain the features and enhancements that are part of Version 3 of AFS. Version 3 of AFS is commercially available and supported by Transarc Corporation, Pittsburgh, PA. */ /* some headers want to have this defined */ #ifdef HAVE_CONFIG_H #include #endif #if !defined(CODA_USE_UCONTEXT) && !defined(HAVE_SIGALTSTACK) #define __ASSEMBLY__ 1 #if defined(sun3) || defined(mc68000) || defined(mc68020) || defined(mc68030) .data /* # # Process assembly language assist for Sun's. # */ .text .even /* # # struct savearea { # char *topstack; # } # */ topstack = 0 /* Stuff to allow saving/restoring registers */ nregs = 13 regs = 0x3ffe | d1-d7 & a0-a5 /* # savecontext(f, area1, newsp) # int (*f)(); struct savearea *area1; char *newsp; */ /* Stack offsets of arguments */ f = 8 area1 = 12 newsp = 16 .globl _savecontext _savecontext: link a6,#-(nregs*4) | Save frame pointer & ... | ... allocate space for nregs registers /* Save registers */ moveml #regs,sp@ movl a6@(area1),a0 | a0 = base of savearea movl sp,a0@(topstack) | area->topstack = sp movl a6@(newsp),d0 | Get new sp jeq noswitch | If newsp == 0, no stack switch movl d0,sp | Switch to new stack noswitch: movl a6@(f),a0 | a0 = f jbsr a0@ | f() /* It is impossible to be here, so segfault */ movb #0,0 /* # returnto(area2) # struct savearea *area2; */ /* Stack offset of argument */ area2 = 8 .globl _returnto _returnto: link a6,#0 movl a6@(area2),a0 | Base of savearea movl a0@(topstack),sp | Restore sp /* Restore registers */ moveml sp@,#regs addl #(nregs*4),sp movl sp,a6 | Argghh...be careful here unlk a6 rts | Return to previous process #endif /* sun3 */ #if defined(sun4) || defined(sparc) || defined(__sparc__) #if defined(__linux__) || defined(__NetBSD__) /* This info from Miguel de Icaza (and SunOS header files/libc) */ #define STACK_ALIGN 8 #define WINDOWSIZE (4*16) #define ARGPUSHSIZE (6*4) #define MINFRAME (WINDOWSIZE+ARGPUSHSIZE+4) /* min frame */ #define SA(X) (((X)+(STACK_ALIGN-1)) & ~(STACK_ALIGN-1)) #ifdef __linux__ #define NAME(x) x #define ENTRY(x) .type x,@function; .global x; x: #include #else /* __NetBSD__ */ #include #include #define NAME(x) _C_LABEL(x) #define ST_FLUSH_WINDOWS T_FLUSHWIN #endif /* __NetBSD__ */ #else #ifdef sun /* Solaris */ #define NAME(x) x #define FUNCTION #function #define _ASM #if 0 /* cpp doesn't always seem to like sys/asm_linkage.h */ #include #else #include #include #define ENTRY(x) .type x,FUNCTION; .global x; x: #endif #else #include #include #endif #endif SAVED_PC = (0*4) SAVED_FP = (1*4) SAVESIZE = (2*4) .seg "text" .align 4 ENTRY(savecontext) save %sp, -SA(MINFRAME + SAVESIZE), %sp t ST_FLUSH_WINDOWS st %i7, [%sp + MINFRAME + SAVED_PC] st %fp, [%sp + MINFRAME + SAVED_FP] tst %i2 be 1f st %sp, [%i1] and %i2, -STACK_ALIGN, %o0 sub %o0, SA(MINFRAME), %sp 1: mov %i0, %l0 call %l0, 0 nop unimp 0 ENTRY(returnto) t ST_FLUSH_WINDOWS ld [%o0], %sp ld [%sp + MINFRAME + SAVED_FP], %fp ld [%sp + MINFRAME + SAVED_PC], %o7 retl restore #endif #ifdef ibm032 .data .globl .oVncs .set .oVncs,0 .globl _savecontext _savecontext: .long _.savecontext .globl _returnto _returnto: .long _.returnto | | Process assembly language assist for Sailboats. | .text .align 2 | | struct savearea { | char *topstack; | } | | Offsets of fields .set topstack,0 | Stuff to allow saving/restoring registers .set regspace,64 .set freg,0 | | savecontext(f, area1, newsp) | int (*f)(); struct savearea *area1; char *newsp; | .globl _.savecontext _.savecontext: ai sp,sp,-regspace | Save frame pointer & ... | ... allocate space for 16 registers | Save registers stm r0,0(sp) | Change this if save fewer regs. | r3 = base of savearea put sp,topstack(r3) | area1->topstack = sp | New sp is in r4. cis r4,0 be L1 | If newsp == 0, no stack switch cas sp,r4,r0 | Switch to new stack L1: get r6,0(r2) | r2 = _f balrx r15,r6 | f() cas r0,r2,r0 | | returnto(area2) | struct savearea *area2; | .globl _.returnto _.returnto: get sp,topstack(r2) | Now in the context of the savecontext stack to be restored. | Start with the registers... lm r0,0(sp) | Change if saving fewer regs. brx r15 | Return to previous process ai sp,sp,regspace .data .ltorg #endif #ifdef vax .data .text /* # # struct savearea { # char *topstack; # } # */ .set topstack,0 /* Stuff to allow saving/restoring registers */ /* # savecontext(f, area1, newsp) # int (*f)(); struct savearea *area1; char *newsp; */ /* Stack offsets of arguments */ .set f,4 .set area1,8 .set newsp,12 .globl _savecontext _savecontext: .word 0x0ffc # Save regs R2-R11 pushl ap # save old ap pushl fp # save old fp movl area1(ap),r0 # r0 = base of savearea movl sp,topstack(r0) # area->topstack = sp movl newsp(ap),r0 # Get new sp beql L1 # if new sp is 0, do not change stacks movl r0,sp # else switch to new stack L1: movl f(ap),r1 # r1 = f calls $0,0(r1) # f() /* It is impossible to be here, so segfault */ movl $0,0 /* # returnto(area2) # struct savearea *area2; */ /* Stack offset of argument */ .set area2,4 .globl _returnto _returnto: .word 0x0 # Who cares about these regs? movl area2(ap),r0 # r0 = address of area2 movl topstack(r0),sp # Restore sp movl (sp)+,fp # Restore fp movl (sp)+,ap # ,,,, ret pushl $1234 # I will gloat, Kazar movl $0,0 #endif #ifdef mips /* Code for MIPS R2000/R3000 architecture * Written by Zalman Stern April 30th, 1989. */ #include #ifndef s8 #define s8 fp #endif /* s8 */ #define regspace 4 + 9 * 4 + 6 * 8 + 4 #define globalptr 0 #define floats 4 #define registers floats + 6 * 8 #define returnaddr regspace - 4 #define topstack 0 .globl savecontext /* MIPS' C compiler doesn't prepend underscores. */ .ent savecontext /* Insert debugger information. */ savecontext: subu sp, regspace .frame sp, regspace, ra /* Save registers. */ sw s0, registers + 0(sp) sw s1, registers + 4(sp) sw s2, registers + 8(sp) sw s3, registers + 12(sp) sw s4, registers + 16(sp) sw s5, registers + 20(sp) sw s6, registers + 24(sp) sw s7, registers + 28(sp) sw s8, registers + 32(sp) /* Save return address */ sw ra, returnaddr(sp) .mask 0xc0ff0000, -4 /* Need to save floating point registers? */ s.d $f20, floats + 0(sp) s.d $f22, floats + 8(sp) s.d $f24, floats + 16(sp) s.d $f26, floats + 24(sp) s.d $f28, floats + 32(sp) s.d $f30, floats + 40(sp) .fmask 0x55400000, regspace sw sp, topstack(a1) beq a2, $0, samestack li t0, -8 and sp, t0, a2 samestack: .cprestore globalptr addu t9, a0, $0 jal a0 .end savecontext .globl returnto .ent returnto returnto: lw sp, topstack(a0) lw s0, registers + 0(sp) lw s1, registers + 4(sp) lw s2, registers + 8(sp) lw s3, registers + 12(sp) lw s4, registers + 16(sp) lw s5, registers + 20(sp) lw s6, registers + 24(sp) lw s7, registers + 28(sp) lw s8, registers + 32(sp) /* Save return address */ lw ra, returnaddr(sp) /* Need to save floating point registers? */ l.d $f20, floats + 0(sp) l.d $f22, floats + 8(sp) l.d $f24, floats + 16(sp) l.d $f26, floats + 24(sp) l.d $f28, floats + 32(sp) l.d $f30, floats + 40(sp) addu sp, regspace j ra .end returnto #endif /* mips */ #if defined(__amd64) #include /* savecontext(f, area1, newsp) int (*f)(); struct savearea *area1; char *newsp; f will be in %rdi *area1 will be in %rsi *newsp will be in %rdx */ .text ENTRY(savecontext) pushq %rsp pushq %rax pushq %rcx pushq %rdx pushq %rbx pushq %rbp pushq %rsi pushq %rdi pushq %r8 pushq %r9 pushq %r10 pushq %r11 pushq %r12 pushq %r13 pushq %r14 pushq %r15 movq %rsp, (%rsi) /* Store sp in savearea. */ cmpq $0, %rdx /* Check if newsp is NULL */ je L1 /* Don't change the stack if newsp is zero. */ movq %rdx, %rsp L1: xorq %rbp, %rbp /* clear stackframe */ call *%rdi /* f(); */ /* Trigger a segfault, we shouldn't get here anyway. */ movq $0, 0 /* returnto(area2) struct savearea *area2; area2 will be in %rdi */ #define area2 8 ENTRY(returnto) mov (%rdi), %rsp /* Restore stack pointer. */ popq %r15 popq %r14 popq %r13 popq %r12 popq %r11 popq %r10 popq %r9 popq %r8 popq %rdi popq %rsi popq %rbp popq %rbx popq %rdx popq %rcx popq %rax popq %rsp ret #endif /* amd64 */ #if defined(i386) /* savecontext(f, area1, newsp) int (*f)(); struct savearea *area1; char *newsp; */ #ifdef __linux__ #include #elif defined(__FreeBSD__) && defined(__ELF__) #include #elif defined(__FreeBSD__) #define ENTRY(x) .align 4; .globl _##x; _##x: #elif defined(__NetBSD__) || defined(__OpenBSD__) #include #elif defined(sun) #define ENTRY(x) \ .align 4; \ .globl x; \ .type x, @function; \ x: #else /* some kind of win32 machine */ #define ENTRY(x) .align 4; .globl _##x; _##x: #endif #define f 36 #define area1 40 #define newsp 44 #define topstack 0 .text ENTRY(savecontext) pusha /* Save registers on the stack. */ movl area1(%esp), %eax /* Load address of savearea. */ movl %esp, topstack(%eax) /* Store sp in savearea. */ movl f(%esp), %eax /* Load f */ movl newsp(%esp), %ecx /* Load the new sp value. */ cmpl $0, %ecx je L1 /* Don't change the stack if newsp is zero. */ movl %ecx, %esp L1: xorl %ebp, %ebp /* clear stackframe */ call *%eax /* f(); */ /* Trigger a segfault, we shouldn't get here anyway. */ movl $0, 0 /* returnto(area2) struct savearea *area2; */ #define area2 4 ENTRY(returnto) movl area2(%esp), %edx /* address of save area. */ movl topstack(%edx), %esp /* Restore stack pointer. */ popa /* Restore registers. */ ret #endif /* i386 */ #ifdef luna88k /* Luna88K Code from Dan Stodolsky via Brad White */ text align 4 global _savecontext _savecontext: /* Allocate stack */ subu r31, r31, 56 /* Save return address */ st r1, r31, 4 /* Save frame pointer */ st r30, r31, 0 /* Set the frame pointer (do I need this?) */ /* or r30, r0, r31*/ /* Save registers */ st r14, r31, 8 st r15, r31, 12 st r16, r31, 16 st r17, r31, 20 st r18, r31, 24 st r19, r31, 28 st r20, r31, 32 st r21, r31, 36 st r22, r31, 40 st r23, r31, 44 st r24, r31, 48 st r25, r31, 52 /* Magic */ st r31, r3, 0 /* area->topstack = sp */ bcnd eq0, r4, @L2 or r31, r0, r4 and r31, r31, 0xfff8 @L2: jsr r2 text align 4 global _returnto _returnto: /* Restore stack pointer */ ld r31, r2, 0 /* Restore return address */ ld r1, r31, 4 /* Restore frame pointer */ ld r30, r31, 0 /* Restore registers */ ld r14, r31, 8 ld r15, r31, 12 ld r16, r31, 16 ld r17, r31, 20 ld r18, r31, 24 ld r19, r31, 28 ld r20, r31, 32 ld r21, r31, 36 ld r22, r31, 40 ld r23, r31, 44 ld r24, r31, 48 ld r25, r31, 52 /* Restore stack size */ addu r31, r31, 56 jmp r1 #endif /* luna88k */ #ifdef __ns32k__ #ifdef __STDC__ #define SYMB(x) _##x: #define EXT(x) _##x #else #define SYMB(x) _/**/x: #define EXT(x) _/**/x #endif /* savecontext(f, area1, newsp) int (*f)(); struct savearea *area1; char *newsp; */ /* Stack offsets of arguments */ f = 8 area1 = 12 newsp = 16 .text .align 2 .globl EXT(savecontext) SYMB(savecontext) enter [r0,r1,r2,r3,r4,r5,r6,r7], 0 # save registers sprd fp, r0 # push frame pointer movd r0, tos movd area1(fp), r0 # save sp to area1 sprd sp, 0(r0) movd f(fp), r0 # get f() movd newsp(fp), r1 # Get new sp cmpd 0, r1 beq noswitch # Set if sp != 0 lprd sp, r1 noswitch: jsr 0(r0) /* should never get here ... */ /* .globl _abort */ /* jsr _abort */ /* returnto(area2) struct savearea *area2; */ area2 = 8 .globl EXT(returnto) SYMB(returnto) enter [], 0 movd area2(fp), r0 lprd sp, 0(r0) movd tos, r0 lprd fp, r0 exit [r0,r1,r2,r3,r4,r5,r6,r7] ret 0 #endif /* __ns32k__ */ #if defined(__arm32__) || defined(__arm__) #ifdef __linux__ #include #define EXT(x) SYMBOL_NAME(x) #else #ifdef __STDC__ #define ENTRY(x) _##x: #define EXT(x) _##x #else #define ENTRY(x) _/**/x: #define EXT(x) _/**/x #endif #endif /* register definitions */ fp .req r11 ip .req r12 sp .req r13 lp .req r14 pc .req r15 /* savecontext(f, area1, newsp) int (*f)(); struct savearea *area1; char *newsp; */ /* Arguments appear as: f in r0, area1 in r1, newsp in r2 */ .text .align 0 .globl EXT(savecontext) .type EXT(savecontext), #function ENTRY(savecontext) @ build the frame mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 @ stack r0 - r10, current fp stmfd sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, fp} str sp, [r1, #0] @ check if newsp is zero movs r2, r2 movne sp, r2 @ call function ... mov pc, r0 /* should never get here ... */ /* bl EXT(abort) */ /* returnto(area2) struct savearea *area2; */ /* area2 is in r0. */ .globl EXT(returnto) .type EXT(returnto), #function ENTRY(returnto) @ restore r0-r10, fp ldr r0, [r0, #0] ldmfd r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, fp} @ return from function call ldmea fp, {fp, sp, pc} #endif /* __arm32__ or __arm__ */ #if defined(__powerpc__) || defined(__ppc__) /* Comments: * 1. Registers R10..R31 and CR0..CR7 are saved * 2. "struct savearea" must hold at least 3 pointers (long) * 3. This code will only work on 32 bit machines (601..604), not 620 * 4. No floating point registers are saved * 5. The save stack "frame" is bigger than absolutely necessary. The * PowerPC [AIX] ABI needs this extra space. */ /* Mach-O assemblers */ #if !defined(NeXT) && !defined(__APPLE__) #define r0 0 #define r1 1 #define r2 2 #define r3 3 #define r4 4 #define r5 5 #define r6 6 #define r7 7 #define r8 8 #define r9 9 #define r10 10 #define r11 11 #define r12 12 #define r13 13 #define r14 14 #define r15 15 #define r16 16 #define r17 17 #define r18 18 #define r19 19 #define r20 20 #define r21 21 #define r22 22 #define r23 23 #define r24 24 #define r25 25 #define r26 26 #define r27 27 #define r28 28 #define r29 29 #define r30 30 #define r31 31 #define EXT(x) x #else /* NeXT && __APPLE__ */ #define EXT(x) _##x #endif /* * savecontext(int (*f)(), struct savearea *save, char *newsp) */ #define FRAME_SIZE (32*4)+(8*4) #define FRAME_OFFSET (8*4) #define TOP_OF_STACK (0*4) #define RETURN (1*4) #define CCR (2*4) .globl EXT(savecontext) EXT(savecontext): subi r1,r1,FRAME_SIZE mfcr r9 stw r9,CCR(r4) stw r10,10*4+FRAME_OFFSET(r1) /* Save registers */ stw r11,11*4+FRAME_OFFSET(r1) stw r12,12*4+FRAME_OFFSET(r1) stw r13,13*4+FRAME_OFFSET(r1) stw r14,14*4+FRAME_OFFSET(r1) stw r15,15*4+FRAME_OFFSET(r1) stw r16,16*4+FRAME_OFFSET(r1) stw r17,17*4+FRAME_OFFSET(r1) stw r18,18*4+FRAME_OFFSET(r1) stw r19,19*4+FRAME_OFFSET(r1) stw r20,20*4+FRAME_OFFSET(r1) stw r21,21*4+FRAME_OFFSET(r1) stw r22,22*4+FRAME_OFFSET(r1) stw r23,23*4+FRAME_OFFSET(r1) stw r24,24*4+FRAME_OFFSET(r1) stw r25,25*4+FRAME_OFFSET(r1) stw r26,26*4+FRAME_OFFSET(r1) stw r27,27*4+FRAME_OFFSET(r1) stw r28,28*4+FRAME_OFFSET(r1) stw r29,29*4+FRAME_OFFSET(r1) stw r30,30*4+FRAME_OFFSET(r1) stw r31,31*4+FRAME_OFFSET(r1) stw r1,TOP_OF_STACK(r4) cmpi 0,r5,0 /* New stack specified? */ mflr r0 stw r0,RETURN(r4) mtlr r3 beq L1 /* No - don't muck with pointer */ /* mr r1,r5 */ addi r1,r5,-FRAME_OFFSET /* leave space for silly linkage info */ L1: blr /* Return */ /* * returnto(struct savearea *area) */ .globl EXT(returnto) EXT(returnto): lwz r1,TOP_OF_STACK(r3) /* Update stack pointer */ lwz r0,RETURN(r3) /* Get return address */ mtlr r0 lwz r4,CCR(r3) mtcrf 0xFF,r4 lwz r10,10*4+FRAME_OFFSET(r1) /* Restore registers */ lwz r11,11*4+FRAME_OFFSET(r1) lwz r12,12*4+FRAME_OFFSET(r1) lwz r13,13*4+FRAME_OFFSET(r1) lwz r14,14*4+FRAME_OFFSET(r1) lwz r15,15*4+FRAME_OFFSET(r1) lwz r16,16*4+FRAME_OFFSET(r1) lwz r17,17*4+FRAME_OFFSET(r1) lwz r18,18*4+FRAME_OFFSET(r1) lwz r19,19*4+FRAME_OFFSET(r1) lwz r20,20*4+FRAME_OFFSET(r1) lwz r21,21*4+FRAME_OFFSET(r1) lwz r22,22*4+FRAME_OFFSET(r1) lwz r23,23*4+FRAME_OFFSET(r1) lwz r24,24*4+FRAME_OFFSET(r1) lwz r25,25*4+FRAME_OFFSET(r1) lwz r26,26*4+FRAME_OFFSET(r1) lwz r27,27*4+FRAME_OFFSET(r1) lwz r28,28*4+FRAME_OFFSET(r1) lwz r29,29*4+FRAME_OFFSET(r1) lwz r30,30*4+FRAME_OFFSET(r1) lwz r31,31*4+FRAME_OFFSET(r1) addi r1,r1,FRAME_SIZE blr #endif /* __powerpc__ */ /* Code for DEC Alpha architecture */ #if defined(__alpha) || defined(__alpha__) #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #else #error "First time alpha port to this platform, hacking time" #endif .globl savecontext .globl returnto #define FSIZE ((8+7+1)*8) /* s0-s6, f0-f7, return */ #define FOFFSET -FSIZE #define REGMASK 0x0400fe00 /* mask for s0-s6 */ #define FREGMASK 0x000003fc /* mask for f2-f9 */ #define SAVED_F2(ptr) 0(ptr) #define SAVED_F3(ptr) 8(ptr) #define SAVED_F4(ptr) 16(ptr) #define SAVED_F5(ptr) 24(ptr) #define SAVED_F6(ptr) 32(ptr) #define SAVED_F7(ptr) 40(ptr) #define SAVED_F8(ptr) 48(ptr) #define SAVED_F9(ptr) 56(ptr) #define SAVED_S0(ptr) 64(ptr) #define SAVED_S1(ptr) 72(ptr) #define SAVED_S2(ptr) 80(ptr) #define SAVED_S3(ptr) 88(ptr) #define SAVED_S4(ptr) 96(ptr) #define SAVED_S5(ptr) 104(ptr) #define SAVED_S6(ptr) 112(ptr) #define SAVED_RA(ptr) 120(ptr) .text .align 3 .ent savecontext,0 savecontext: .frame sp, FSIZE, ra ldgp gp, 0(pv) lda sp, -FSIZE(sp) stq s0, SAVED_S0(sp) stq s1, SAVED_S1(sp) stq s2, SAVED_S2(sp) stq s3, SAVED_S3(sp) stq s4, SAVED_S4(sp) stq s5, SAVED_S5(sp) stq s6, SAVED_S6(sp) stq ra, SAVED_RA(sp) .mask REGMASK, -FSIZE /* Save floating point registers */ stt $f2, SAVED_F2(sp) stt $f3, SAVED_F3(sp) stt $f4, SAVED_F4(sp) stt $f5, SAVED_F5(sp) stt $f6, SAVED_F6(sp) stt $f7, SAVED_F7(sp) stt $f8, SAVED_F8(sp) stt $f9, SAVED_F9(sp) .prologue 1 stq sp, 0(a1) or a0,zero,pv /* call point in pv */ beq a2, samestack or a2,zero,sp /* switch stack */ samestack: jsr ra,(pv),0 /* off we go */ .end savecontext .align 3 .text .ent returnto returnto: .frame sp, 0, ra ldgp gp,0(pv) .prologue 1 ldq sp, 0(a0) /* Restore callee-saved regs */ ldq s0, SAVED_S0(sp) ldq s1, SAVED_S1(sp) ldq s2, SAVED_S2(sp) ldq s3, SAVED_S3(sp) ldq s4, SAVED_S4(sp) ldq s5, SAVED_S5(sp) ldq s6, SAVED_S6(sp) /* Return address */ ldq ra, SAVED_RA(sp) /* Floating point registers */ ldt $f2, SAVED_F2(sp) ldt $f3, SAVED_F3(sp) ldt $f4, SAVED_F4(sp) ldt $f5, SAVED_F5(sp) ldt $f6, SAVED_F6(sp) ldt $f7, SAVED_F7(sp) ldt $f8, SAVED_F8(sp) ldt $f8, SAVED_F9(sp) lda sp, FSIZE(sp) ret zero,(ra),1 .end returnto #endif /* DEC Alpha */ #endif /* !defined(HAVE_UCONTEXT_H) && !defined(HAVE_SIGALTSTACK) */