summaryrefslogtreecommitdiffstats
path: root/private/crt32/misc/i386/longjmp.asm
blob: ae236afff5c6864b2a47bc4ffcd94c62448d5fd5 (plain) (blame)
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
;***
;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