;***
;longjmp.asm
;
;	Copyright (C) 1994 Microsoft Corporation. All rights reserved.
;
;Purpose:
;	Contains setjmp(), longjmp() & raisex() routines;
;	split from exsup.asm for granularity purposes.
;
;Notes:
;
;Revision History:
;	01-12-94  PML	Split from setjmp.asm, added C9.0 generic EH
;			callback for unwind.
;
;*******************************************************************************

;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;

;Define small32 and flat32 since these are not defined in the NT build process
small32 equ 1
flat32  equ 1

.xlist
include pversion.inc
?DFDATA =	1
?NODATA =	1
include cmacros.mas
include exsup.inc
.list

BeginDATA

COMM    __setjmpexused:dword

EndDATA

assumes DS,DATA
assumes FS,DATA

BeginCODE
if	@Version LT 600
;this needs to go here to work around a masm5 bug. (emits wrong fixup)
assumes CS,FLAT
endif

; Following symbols defined in exsup.asm, sehsupp.c
extrn __except_list:near
extrn __global_unwind2:near
extrn __local_unwind2:near
extrn __rt_probe_read4@4:near

; int
; longjmp (
;	IN jmp_buf env
;	IN int val)
;
; Routine Description:
;
;	Restore the stack and register environment saved by _setjmp.
;	Reloads callee-save registers and stack pointer to that saved in
;	the jmp_buf, then returns to the point of the _setjmp call.
;
;	If exception unwinding is enabled, also reload the exception state
;	from the jmp_buf by doing an unwind (both global and local) back
;	to the old state.  Do so by checking for a new-format (C9.0)
;	jmp_buf, and call the EH longjmp unwinder saved therein if
;	found, else assume a C8.0-vintage jmp_buf and SEH.
;
; Arguments:
;
;	env - Address of the buffer holding the reload state
;	val - Value to return from the _setjmp callsite (if nonzero)
;
; Return Value:
;
;	None.  longjmp does not return directly, but instead continues
;	execution from the point of the _setjmp used to initialize the
;	jmp_buf.  That call will return the 'val' parameter if nonzero,
;	else a one.

cProc longjmp,<C,PUBLIC>
cBegin
        mov     ebx, [esp+4]            ;get jmp_buf

        ;restore ebp before possible call to local_unwind-er
        ; the call to global/local unwind will preserve this (callee save).
	mov	ebp, [ebx.saved_ebp]	;set up bp
ifdef	_NTSDK
	cmp	__setjmpexused, 0
        je      short _lj_no_unwind
endif
        mov     esi, [ebx.saved_xregistration]
        cmp     esi, dword ptr fs:__except_list
	je	short _lj_local_unwind

        push    esi
        call    __global_unwind2
        add     esp,4

_lj_local_unwind:
        cmp     esi, 0
	je	short _lj_no_unwind

	; Check if called with old or new format jmp_buf.  Look for the
	; version cookie that's only present in the new format.
	lea	eax, [ebx.version_cookie]
	push	eax
	call	__rt_probe_read4@4
	or	eax, eax
	jz	short _lj_old_unwind
	mov	eax, [ebx.version_cookie]
	cmp	eax, JMPBUF_COOKIE
	jnz	short _lj_old_unwind

	; Called with a new-format jmp_buf.  Call unwind function supplied
	; to the jmp_buf at setjmp time.
	mov	eax, [ebx.unwind_func]
	or	eax, eax
	jz	short _lj_no_unwind	;no local unwind necessary
	push	ebx
	call	eax
	jmp	short _lj_no_unwind

	; Called with an old-format jmp_buf.  Duplicate old longjmp behavior,
	; assuming there's a C8.0 SEH node at top.
_lj_old_unwind:
        mov	eax, [ebx.saved_trylevel]
	push	eax
        push    esi
        call    __local_unwind2
        add     esp, 8

_lj_no_unwind:
        mov     edx, ebx
        mov     ebx, [edx.saved_ebx]    ;recover registers...
        mov     edi, [edx.saved_edi]
        mov     esi, [edx.saved_esi]

        mov     eax, [esp+8]		;load the return value
	cmp	eax, 1			;make sure it's not 0
	adc	eax, 0

        mov     esp, [edx.saved_esp]    ;here, sp gets scorched
        add     esp, 4                  ;punt the (old) return address
        jmp     [edx.saved_return]      ;return
cEnd

EndCODE
END
