//++ // // Copyright (c) 1993 IBM Corporation and Microsoft Corporation // // Module Name: // // setjmpex.s // // Abstract: // // This module implements the MIPS specific routine to provide SAFE // handling of setjmp/longjmp with respect to structured exception // handling. // // Author: // // Rick Simpson 13-Oct-1993 // // based on MIPS version by David N. Cutler (davec) 2-Apr-1993 // // Environment: // // Any mode. // // Revision History: // // Tom Wood 23-Aug-1994 // Add stack limit parameters to RtlVirtualUnwind. //-- //list(off) #include "ksppc.h" //list(on) .extern ..RtlLookupFunctionEntry .extern ..RtlVirtualUnwind // // Define variable that will cause setjmp/longjmp to be safe with respect // to structured exception handling. // .globl _setjmpexused .data _setjmpexused: .long .._setjmpex // set address of safe setjmp routine //++ // // int // _setjmpex ( // IN jmp_buf JumpBuffer // ) // // Routine Description: // // This function transfers control to the actual setjmp routine. // // Arguments: // // JumpBuffer (r.3) - Supplies the address of a jump buffer to store the // jump information. // // Return Value: // // A value of zero is returned. // //-- // Stack frame definition: .struct 0 SjBackChain: .space 4 // chain to previous stack frame .space 5*4 // rest of standard stack frame header .space 8*4 // standard outgoing arg area .align 3 // ensure 8-byte boundary SjCtxt: .space ContextFrameLength // context frame SjFl: .space 4 // in function flag variable .align 3 // ensure that overall length // will be a multiple of 8 SjReturnAddr: .space 4 // space for saved LR (prologue will // store it here) .space 4 // space for saved r.31 SetjmpFrameLength: NESTED_ENTRY (_setjmpex,SetjmpFrameLength,1,0) PROLOGUE_END (_setjmpex) // // Save the nonvolatile machine state in the context record // // skip Fprs as all we are really trying to do here is prime the // pump for RtlVirtualUnwind. stw r.13, CxGpr13 + SjCtxt (r.sp) // save n-v general regs stw r.14, CxGpr14 + SjCtxt (r.sp) stw r.15, CxGpr15 + SjCtxt (r.sp) stw r.16, CxGpr16 + SjCtxt (r.sp) stw r.17, CxGpr17 + SjCtxt (r.sp) stw r.18, CxGpr18 + SjCtxt (r.sp) stw r.19, CxGpr19 + SjCtxt (r.sp) stw r.20, CxGpr20 + SjCtxt (r.sp) stw r.21, CxGpr21 + SjCtxt (r.sp) stw r.22, CxGpr22 + SjCtxt (r.sp) stw r.23, CxGpr23 + SjCtxt (r.sp) stw r.24, CxGpr24 + SjCtxt (r.sp) stw r.25, CxGpr25 + SjCtxt (r.sp) stw r.26, CxGpr26 + SjCtxt (r.sp) stw r.27, CxGpr27 + SjCtxt (r.sp) stw r.28, CxGpr28 + SjCtxt (r.sp) stw r.29, CxGpr29 + SjCtxt (r.sp) stw r.30, CxGpr30 + SjCtxt (r.sp) stw r.31, CxGpr31 + SjCtxt (r.sp) mr r.31, r.3 // save incoming jump buffer pointer lwz r.3, SjReturnAddr (r.sp) // pick up return addr to caller la r.0, SetjmpFrameLength (r.sp) // save caller's stack frame pointer stw r.0, CxGpr1 + SjCtxt (r.sp) stw r.3, CxIar + SjCtxt (r.sp) // save resume addr in context stw r.3, 4 (r.31) // save resume addr in 2nd word of jmpbuf stw r.sp, JbType (r.31) // set "safe setjmp" flag in jump buffer // // Perform unwind to determine the virtual frame pointer of the caller. // subi r.3, r.3, 4 // compute control PC address bl ..RtlLookupFunctionEntry // lookup function table address .znop ..RtlLookupFunctionEntry mr r.4, r.3 // set returned value as 2nd arg lwz r.3, SjReturnAddr (r.sp) // pick up return address again la r.5, SjCtxt (r.sp) // context record addr is 3rd arg la r.6, SjFl (r.sp) // addr of in-func flag is 4th arg subi r.3, r.3, 4 // compute control PC address as 1st arg mr r.7, r.31 // addr of 1st word of jmpbuf is 5th arg // (virt frame pointer will be stored here) li r.8, 0 // ctxt pointers (NULL) is 6th arg li r.9, 0 // low stack limit is 7th arg li r.10, -1 // high stack limit is 8th arg bl ..RtlVirtualUnwind // compute virtual frame pointer value .znop ..RtlVirtualUnwind // // If we were called via a thunk the Establisher Frame derived by // RtlVirtualUnwind will be equal to the current stack frame. If // this is the case we need to unwind one more level, also, the // ControlPc returned by RtlVirtualUnwind (+4) should be used as // the resume address. // // Note: this requirement will go away if we adopt the glue proposal // that returns directly to the caller (caller reloades toc). // (plj 3/26/94) lwz r.7, 0(r.31) // Establisher Frame addi r.8, r.sp, SetjmpFrameLength // caller's sp cmplw r.7, r.8 bne SjDone // Save returned value (+4) as resume address in jump buffer addi r.8, r.3, 4 stw r.8, 4(r.31) // Unwind one more level to get the "real" establisher frame. bl ..RtlLookupFunctionEntry // lookup function table address .znop ..RtlLookupFunctionEntry mr r.4, r.3 // set returned value as 2nd arg lwz r.3, 4(r.31) // pick up ControlPc again la r.5, SjCtxt(r.sp) // &context record la r.6, SjFl(r.sp) // addr of in-func flag mr r.7, r.31 // & 1st word of jmpbuf li r.8, 0 // ctxt pointers (NULL) li r.9, 0 // low stack limit li r.10, -1 // high stack limit subi r.3, r.3, 4 // unadjust ControlPc bl ..RtlVirtualUnwind // compute & frame pointer .znop ..RtlVirtualUnwind // // Set return value, restore registers, deallocate stack frame, and return. // SjDone: li r.3, 0 // set return value of 0 NESTED_EXIT (_setjmpex,SetjmpFrameLength,1,0)