summaryrefslogtreecommitdiffstats
path: root/private/crt32/misc/mips
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/crt32/misc/mips
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/crt32/misc/mips')
-rw-r--r--private/crt32/misc/mips/chandler.c219
-rw-r--r--private/crt32/misc/mips/jmpuwind.s138
-rw-r--r--private/crt32/misc/mips/longjmp.s128
-rw-r--r--private/crt32/misc/mips/setjmp.s101
-rw-r--r--private/crt32/misc/mips/setjmpex.s156
5 files changed, 742 insertions, 0 deletions
diff --git a/private/crt32/misc/mips/chandler.c b/private/crt32/misc/mips/chandler.c
new file mode 100644
index 000000000..4721f82b1
--- /dev/null
+++ b/private/crt32/misc/mips/chandler.c
@@ -0,0 +1,219 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ chandler.c
+
+Abstract:
+
+ This module implements the C specific exception handler that provides
+ structured condition handling for the C language.
+
+Author:
+
+ David N. Cutler (davec) 11-Sep-1990
+
+Environment:
+
+ Any mode.
+
+Revision History:
+
+--*/
+
+#include "nt.h"
+
+
+//
+// Define procedure prototypes for exception filter and termination handler
+// execution routines defined in jmpunwnd.s
+//
+
+LONG
+__C_ExecuteExceptionFilter (
+ PEXCEPTION_POINTERS ExceptionPointers,
+ EXCEPTION_FILTER ExceptionFilter,
+ ULONG EstablisherFrame
+ );
+
+VOID
+__C_ExecuteTerminationHandler (
+ BOOLEAN AbnormalTermination,
+ TERMINATION_HANDLER TerminationHandler,
+ ULONG EstablisherFrame
+ );
+
+EXCEPTION_DISPOSITION
+__C_specific_handler (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PVOID EstablisherFrame,
+ IN OUT PCONTEXT ContextRecord,
+ IN OUT PDISPATCHER_CONTEXT DispatcherContext
+ )
+
+/*++
+
+Routine Description:
+
+ This function scans the scope tables associated with the specified
+ procedure and calls exception and termination handlers as necessary.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to an exception record.
+
+ EstablisherFrame - Supplies a pointer to frame of the establisher function.
+
+ ContextRecord - Supplies a pointer to a context record.
+
+ DispatcherContext - Supplies a pointer to the exception dispatcher or
+ unwind dispatcher context.
+
+Return Value:
+
+ If the exception is handled by one of the exception filter routines, then
+ there is no return from this routine and RtlUnwind is called. Otherwise,
+ an exception disposition value of continue execution or continue search is
+ returned.
+
+--*/
+
+{
+
+ ULONG ControlPc;
+ EXCEPTION_FILTER ExceptionFilter;
+ EXCEPTION_POINTERS ExceptionPointers;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG Index;
+ PSCOPE_TABLE ScopeTable;
+ ULONG TargetPc;
+ TERMINATION_HANDLER TerminationHandler;
+ LONG Value;
+
+ //
+ // Get address of where control left the establisher, the address of the
+ // function table entry that describes the function, and the address of
+ // the scope table.
+ //
+
+ ControlPc = DispatcherContext->ControlPc;
+ FunctionEntry = DispatcherContext->FunctionEntry;
+ ScopeTable = (PSCOPE_TABLE)(FunctionEntry->HandlerData);
+
+ //
+ // If an unwind is not in progress, then scan the scope table and call
+ // the appropriate exception filter routines. Otherwise, scan the scope
+ // table and call the appropriate termination handlers using the target
+ // PC obtained from the context record.
+ // are called.
+ //
+
+ if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) {
+
+ //
+ // Scan the scope table and call the appropriate exception filter
+ // routines.
+ //
+
+ ExceptionPointers.ExceptionRecord = ExceptionRecord;
+ ExceptionPointers.ContextRecord = ContextRecord;
+ for (Index = 0; Index < ScopeTable->Count; Index += 1) {
+ if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) &&
+ (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) {
+
+ //
+ // Call the exception filter routine.
+ //
+
+ ExceptionFilter =
+ (EXCEPTION_FILTER)ScopeTable->ScopeRecord[Index].HandlerAddress;
+ Value = __C_ExecuteExceptionFilter(&ExceptionPointers,
+ ExceptionFilter,
+ (ULONG)EstablisherFrame);
+
+ //
+ // If the return value is less than zero, then dismiss the
+ // exception. Otherwise, if the value is greater than zero,
+ // then unwind to the target exception handler. Otherwise,
+ // continue the search for an exception filter.
+ //
+
+ if (Value < 0) {
+ return ExceptionContinueExecution;
+
+ } else if (Value > 0) {
+ RtlUnwind(EstablisherFrame,
+ (PVOID)ScopeTable->ScopeRecord[Index].JumpTarget,
+ ExceptionRecord,
+ (PVOID)ExceptionRecord->ExceptionCode);
+ }
+ }
+ }
+
+ } else {
+
+ //
+ // Scan the scope table and call the appropriate termination handler
+ // routines.
+ //
+
+ TargetPc = ContextRecord->Fir;
+ for (Index = 0; Index < ScopeTable->Count; Index += 1) {
+ if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) {
+
+ //
+ // If the target PC is within the same scope the control PC
+ // is within, then this is an uplevel goto out of an inner try
+ // scope or a long jump back into a try scope. Terminate the
+ // scan termination handlers.
+ //
+ // N.B. The target PC can be just beyond the end of the scope,
+ // in which case it is a leave from the scope.
+ //
+
+
+ if ((TargetPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (TargetPc <= ScopeTable->ScopeRecord[Index].EndAddress)) {
+ break;
+
+ } else {
+
+ //
+ // If the scope table entry describes an exception filter
+ // and the associated exception handler is the target of
+ // the unwind, then terminate the scan for termination
+ // handlers. Otherwise, if the scope table entry describes
+ // a termination handler, then record the address of the
+ // end of the scope as the new control PC address and call
+ // the termination handler.
+ //
+
+ if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) {
+ if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) {
+ break;
+ }
+
+ } else {
+ DispatcherContext->ControlPc =
+ ScopeTable->ScopeRecord[Index].EndAddress + 4;
+ TerminationHandler =
+ (TERMINATION_HANDLER)ScopeTable->ScopeRecord[Index].HandlerAddress;
+ __C_ExecuteTerminationHandler(TRUE,
+ TerminationHandler,
+ (ULONG)EstablisherFrame);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Continue search for exception or termination handlers.
+ //
+
+ return ExceptionContinueSearch;
+}
diff --git a/private/crt32/misc/mips/jmpuwind.s b/private/crt32/misc/mips/jmpuwind.s
new file mode 100644
index 000000000..8e99fcc4c
--- /dev/null
+++ b/private/crt32/misc/mips/jmpuwind.s
@@ -0,0 +1,138 @@
+// TITLE("Jump to Unwind")
+//++
+//
+// Copyright (c) 1992 Microsoft Corporation
+//
+// Module Name:
+//
+// jmpuwind.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to jump to the runtime
+// time library unwind routine.
+//
+// Author:
+//
+// David N. Cutler (davec) 12-Sep-1990
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+ SBTTL("Execute Exception Filter")
+//++
+//
+// ULONG
+// __C_ExecuteExceptionFilter (
+// PEXCEPTION_POINTERS ExceptionPointers,
+// EXCEPTION_FILTER ExceptionFilter,
+// ULONG EstablisherFrame
+// )
+//
+// Routine Description:
+//
+// This function sets the static link and transfers control to the specified
+// exception filter routine.
+//
+// Arguments:
+//
+// ExceptionPointers (a0) - Supplies a pointer to the exception pointers
+// structure.
+//
+// ExceptionFilter (a1) - Supplies the address of the exception filter
+// routine.
+//
+// EstablisherFrame (a2) - Supplies the establisher frame pointer.
+//
+// Return Value:
+//
+// The value returned by the exception filter routine.
+//
+//--
+
+ LEAF_ENTRY(__C_ExecuteExceptionFilter)
+
+ move v0,a2 // set static link
+ j a1 // transfer control to exception filter
+
+ .end __C_ExecuteExceptionFilter
+
+ SBTTL("Execute Termination Handler")
+//++
+//
+// VOID
+// __C_ExecuteTerminationHandler (
+// BOOLEAN AbnormalTermination,
+// TERMINATION_HANDLER TerminationHandler,
+// ULONG EstablisherFrame
+// )
+//
+// Routine Description:
+//
+// This function sets the static link and transfers control to the specified
+// termination handler routine.
+//
+// Arguments:
+//
+// AbnormalTermination (a0) - Supplies a boolean value that determines
+// whether the termination is abnormal.
+//
+// TerminationHandler (a1) - Supplies the address of the termination handler
+// routine.
+//
+// EstablisherFrame (a2) - Supplies the establisher frame pointer.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(__C_ExecuteTerminationHandler)
+
+ move v0,a2 // set static link
+ j a1 // transfer control to termination handler
+
+ .end __C_ExecuteTerminationHandler
+
+ SBTTL("Jump to Unwind")
+//++
+//
+// VOID
+// __jump_unwind (
+// IN PVOID EstablishFrame,
+// IN PVOID TargetPc
+// )
+//
+// Routine Description:
+//
+// This function transfer control to unwind. It is used by the MIPS
+// compiler when a goto out of the body or a try statement occurs.
+//
+// Arguments:
+//
+// EstablishFrame (a0) - Supplies the establisher frame point of the
+// target of the unwind.
+//
+// TargetPc (a1) - Supplies the target instruction address where control
+// is to be transfered to after the unwind operation is complete.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(__jump_unwind)
+
+ move a2,zero // set NULL exception record address
+ move a3,zero // set destination return value
+ j RtlUnwind // unwind to specified target
+
+ .end __jump_unwind
diff --git a/private/crt32/misc/mips/longjmp.s b/private/crt32/misc/mips/longjmp.s
new file mode 100644
index 000000000..04e886570
--- /dev/null
+++ b/private/crt32/misc/mips/longjmp.s
@@ -0,0 +1,128 @@
+// TITLE("Long Jump")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+//
+// Module Name:
+//
+// longjmp.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to perform a long
+// jump operation.
+//
+// N.B. This routine conditionally provides UNSAFE handling of longjmp
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an unitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// David N. Cutler (davec) 2-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+ SBTTL("Long Jump")
+//++
+//
+// int
+// longjmp (
+// IN jmp_buf JumpBuffer,
+// IN int ReturnValue
+// )
+//
+// Routine Description:
+//
+// This function performs a long jump to the context specified by the
+// jump buffer.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer that contains
+// jump information.
+//
+// ReturnValue (a1) - Supplies the value that is to be returned to the
+// caller of set jump.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+ .space 4 * 4 // argument save area
+LjEr: .space ExceptionRecordLength // exception record
+ .space 4 * 3 // fill
+LjRa: .space 4 // saved return address
+LongjmpFrameLength:
+
+ NESTED_ENTRY(longjmp, LongjmpFrameLength, zero)
+
+ subu sp,sp,LongjmpFrameLength // allocate stack frame
+ sw ra,LjRa(sp) // save return address
+
+ PROLOGUE_END
+
+ bne zero,a1,10f // if ne, return value specified
+ li a1,1 // set return value to nonzero value
+10: lw v0,JbType(a0) // get safe setjmp/longjmp flag
+ bne zero,v0,20f // if ne, provide safe longjmp
+
+//
+// Provide unsafe handling of longjmp.
+//
+
+ move v0,a1 // set return value
+ ldc1 f20,JbFltF20(a0) // restore floating registers f20 - f31
+ ldc1 f22,JbFltF22(a0) //
+ ldc1 f24,JbFltF24(a0) //
+ ldc1 f26,JbFltF26(a0) //
+ ldc1 f28,JbFltF28(a0) //
+ ldc1 f30,JbFltF30(a0) //
+ lw s0,JbIntS0(a0) // restore integer registers s0 - s8
+ lw s1,JbIntS1(a0) //
+ lw s2,JbIntS2(a0) //
+ lw s3,JbIntS3(a0) //
+ lw s4,JbIntS4(a0) //
+ lw s5,JbIntS5(a0) //
+ lw s6,JbIntS6(a0) //
+ lw s7,JbIntS7(a0) //
+ lw s8,JbIntS8(a0) //
+ lw a1,JbFir(a0) // get setjmp return address
+ lw sp,JbIntSp(a0) // restore stack pointer
+ j a1 // jump back to setjmp site
+
+//
+// Provide safe handling of longjmp.
+//
+// An exception record is constructed that contains a log jump status
+// code and the first exception information parameter is a pointer to
+// the jump buffer.
+//
+
+20: li v0,STATUS_LONGJUMP // get long jump status code
+ sw v0,LjEr + ErExceptionCode(sp) // set exception code
+ sw zero,LjEr + ErExceptionFlags(sp) // clear exception flags
+ sw zero,LjEr + ErExceptionRecord(sp) // clear associate record
+ sw zero,LjEr + ErExceptionAddress(sp) // clear exception address
+ li v0,1 // set number of parameters
+ sw v0,LjEr + ErNumberParameters(sp) //
+ sw a0,LjEr + ErExceptionInformation(sp) // set jump buffer address
+ move a3,a1 // set return value
+ addu a2,sp,LjEr // compute exception record address
+ lw a1,JbFir(a0) // set target instruction address
+ lw a0,JbType(a0) // set target virtual frame address
+ jal RtlUnwind // finish in common code
+ b 20b
+
+ .end longjmp
diff --git a/private/crt32/misc/mips/setjmp.s b/private/crt32/misc/mips/setjmp.s
new file mode 100644
index 000000000..245cd4b37
--- /dev/null
+++ b/private/crt32/misc/mips/setjmp.s
@@ -0,0 +1,101 @@
+// TITLE("Set Jump")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+//
+// Module Name:
+//
+// setjmp.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to perform a setjmp.
+//
+// N.B. This module conditionally provides UNSAFE handling of setjmp and
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an uninitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// David N. Cutler (davec) 7-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+//
+// Define variable that will cause setjmp/longjmp to be safe or unsafe with
+// respect to structured exception handling.
+//
+
+ .globl _setjmpexused
+ .comm _setjmpexused , 4
+
+ SBTTL("Set Jump")
+//++
+//
+// int
+// setjmp (
+// IN jmp_buf JumpBuffer
+// )
+//
+// Routine Description:
+//
+// This function saved the current nonvolatile register state in the
+// specified jump buffer and returns a function vlaue of zero.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ LEAF_ENTRY(setjmp)
+
+ lw v0,_setjmpexused // get value of switch variable
+ bne zero,v0,10f // if ne, provide safe setjmp
+
+//
+// Provide unsafe handling of setjmp.
+//
+
+ sdc1 f20,JbFltF20(a0) // save floating registers f20 - f31
+ sdc1 f22,JbFltF22(a0) //
+ sdc1 f24,JbFltF24(a0) //
+ sdc1 f26,JbFltF26(a0) //
+ sdc1 f28,JbFltF28(a0) //
+ sdc1 f30,JbFltF30(a0) //
+ sw s0,JbIntS0(a0) // save integer registers s0 - s8
+ sw s1,JbIntS1(a0) //
+ sw s2,JbIntS2(a0) //
+ sw s3,JbIntS3(a0) //
+ sw s4,JbIntS4(a0) //
+ sw s5,JbIntS5(a0) //
+ sw s6,JbIntS6(a0) //
+ sw s7,JbIntS7(a0) //
+ sw s8,JbIntS8(a0) //
+ sw ra,JbFir(a0) // get setjmp return address
+ sw sp,JbIntSp(a0) // save stack pointer
+ sw zero,JbType(a0) // clean safe setjmp flag
+ move v0,zero // set return value
+ j ra // return
+
+//
+// Provide safe handling of setjmp.
+//
+
+10: j v0 // finish in common code
+
+ .end setjmp
diff --git a/private/crt32/misc/mips/setjmpex.s b/private/crt32/misc/mips/setjmpex.s
new file mode 100644
index 000000000..31385e394
--- /dev/null
+++ b/private/crt32/misc/mips/setjmpex.s
@@ -0,0 +1,156 @@
+// TITLE("Set Jump Extended")
+//++
+//
+// Copyright (c) 1993 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:
+//
+// David N. Cutler (davec) 2-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+//
+// Define variable that will cause setjmp/longjmp to be safe with respect
+// to structured exception handling.
+//
+
+ .globl _setjmpexused
+ .data
+_setjmpexused:
+ .word _setjmpex // set address of safe setjmp routine
+
+ SBTTL("Set Jump Extended")
+//++
+//
+// int
+// _setjmpex (
+// IN jmp_buf JumpBuffer
+// )
+//
+// Routine Description:
+//
+// This function transfers control to the actual setjmp routine.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ .struct 0
+ .space 4 * 4 // argument save area
+SjS0: .space 4 // saved integer register s0
+SjFl: .space 4 // in function flag variable
+ .space 4 // fill
+SjRa: .space 4 // saved return address
+SetjmpFrameLength:
+
+ NESTED_ENTRY(_setjmpex, SetjmpFrameLength, zero)
+
+ subu sp,sp,SetjmpFrameLength // allocate stack frame
+ sw s0,SjS0(sp) // save integer register s0
+ sw ra,SjRa(sp) // save return address
+ move s0,sp // set frame pointer
+
+ PROLOGUE_END
+
+ subu sp,sp,ContextFrameLength + 16 // allocate a context frame
+
+//
+// Save the nonvolatile machine state in both the jump buffer and a context
+// record that will be used to compute the virtual frame pointer.
+//
+
+ sdc1 f20,JbFltF20(a0) // save floating registers f20 - f31
+ sdc1 f22,JbFltF22(a0) //
+ sdc1 f24,JbFltF24(a0) //
+ sdc1 f26,JbFltF26(a0) //
+ sdc1 f28,JbFltF28(a0) //
+ sdc1 f30,JbFltF30(a0) //
+ lw v0,SjS0(s0) // get saved integer register s0
+ sw v0,JbIntS0(a0) // save integer registers s0 - s8
+ sw s1,JbIntS1(a0) //
+ sw s2,JbIntS2(a0) //
+ sw s3,JbIntS3(a0) //
+ sw s4,JbIntS4(a0) //
+ sw s5,JbIntS5(a0) //
+ sw s6,JbIntS6(a0) //
+ sw s7,JbIntS7(a0) //
+ sw s8,JbIntS8(a0) //
+ sw ra,JbFir(a0) // get setjmp return address
+ addu v0,s0,SetjmpFrameLength // compute stack pointer address
+ sw v0,JbIntSp(a0) // save stack pointer
+
+ sdc1 f20,CxFltF20 + 16(sp) // save floating registers f20 - f31
+ sdc1 f22,CxFltF22 + 16(sp) //
+ sdc1 f24,CxFltF24 + 16(sp) //
+ sdc1 f26,CxFltF26 + 16(sp) //
+ sdc1 f28,CxFltF28 + 16(sp) //
+ sdc1 f30,CxFltF30 + 16(sp) //
+ lw v0,SjS0(s0) // get saved integer register s0
+ sw v0,CxIntS0 + 16(sp) // save integer registers s0 - s8
+ sw s1,CxIntS1 + 16(sp) //
+ sw s2,CxIntS2 + 16(sp) //
+ sw s3,CxIntS3 + 16(sp) //
+ sw s4,CxIntS4 + 16(sp) //
+ sw s5,CxIntS5 + 16(sp) //
+ sw s6,CxIntS6 + 16(sp) //
+ sw s7,CxIntS7 + 16(sp) //
+ sw s8,CxIntS8 + 16(sp) // save integer register s8
+ sw gp,CxIntGp + 16(sp) // save integer register gp
+ addu v0,s0,SetjmpFrameLength // compute stack pointer address
+ sw v0,CxIntSp + 16(sp) // save stack pointer
+ sw ra,CxIntRa + 16(sp) // save return address
+ sw ra,CxFir + 16(sp) // save return address
+
+//
+// Perform unwind to determine the virtual frame pointer of the caller.
+//
+
+ addu a0,a0,JbType // set virtual frame address argument
+ sw a0,4 * 4(sp) //
+ subu a0,ra,4 // compute control PC address
+ jal RtlLookupFunctionEntry // lookup function table address
+ lw a0,SjRa(s0) // get return address
+ subu a0,a0,4 // compute control PC address
+ move a1,v0 // set address of function entry
+ addu a2,sp,16 // compute address of context record
+ addu a3,s0,SjFl // set address of in function variable
+ sw zero,4 * 5(sp) // set context pointer array address
+ jal RtlVirtualUnwind // compute virtual frame pointer value
+
+//
+// Set return value, restore registers, deallocate stack frame, and return.
+//
+
+ move v0,zero // set return value
+ move sp,s0 // reset stack pointer
+ lw s0,SjS0(sp) // restore integer register s0
+ lw ra,SjRa(sp) // restore return address
+ addu sp,sp,SetjmpFrameLength // deallocate stack frame
+ j ra // return
+
+ .end _setjmpex