summaryrefslogtreecommitdiffstats
path: root/private/crt32/misc/ppc/setjmpex.s
blob: 063f8fa68e50c72da8506b4f7dce5b9b33d523bb (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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
//++
//
// 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)