e795c42da9d44d307a922cb0b9050497d10699a1
[kopensolaris-gnu/glibc.git] / sysdeps / vax / __longjmp.c
1 /* Copyright (C) 1991, 1992, 1994, 1997 Free Software Foundation, Inc.
2    Derived from @(#)_setjmp.s   5.7 (Berkeley) 6/27/88,
3    Copyright (c) 1980 Regents of the University of California.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <setjmp.h>
21
22 #ifndef __GNUC__
23   #error This file uses GNU C extensions; you must compile with GCC.
24 #endif
25
26
27 #define REI     02      /* Vax `rei' opcode.  */
28
29 /* Jump to the position specified by ENV, causing the
30    setjmp call there to return VAL, or 1 if VAL is 0.  */
31 __NORETURN
32 void
33 __longjmp (env, val)
34      const __jmp_buf env;
35      int val;
36 {
37   register long int *fp asm("fp");
38   long int *regsave;
39   unsigned long int flags;
40
41   if (env.__fp == NULL)
42     __libc_fatal("longjmp: Invalid ENV argument.\n");
43
44   if (val == 0)
45     val = 1;
46
47   asm volatile("loop:");
48
49   flags = *(long int *) (6 + (char *) fp);
50   regsave = (long int *) (20 + (char *) fp);
51   if (flags & 1)
52     /* R0 was saved by the caller.
53        Store VAL where it will be restored from.  */
54     *regsave++ = val;
55   if (flags & 2)
56     /* R1 was saved by the caller.
57        Store ENV where it will be restored from.  */
58     *regsave = env;
59
60   /* Was the FP saved in the last call the same one in ENV?  */
61   asm volatile("cmpl %0, 12(fp);"
62                /* Yes, return to it.  */
63                "beql done;"
64                /* The FP in ENV is less than the one saved in the last call.
65                   This means we have already returned from the function that
66                   called `setjmp' with ENV!  */
67                "blssu latejump;" : /* No outputs.  */ : "g" (env.__fp));
68
69   /* We are more than one level below the state in ENV.
70      Return to where we will pop another stack frame.  */
71   asm volatile("movl $loop, 16(fp);"
72                "ret");
73
74   asm volatile("done:");
75   {
76     char return_insn asm("*16(fp)");
77     if (return_insn == REI)
78       /* We're returning with an `rei' instruction.
79          Do a return with PSL-PC pop.  */
80       asm volatile("movab 0f, 16(fp)");
81     else
82       /* Do a standard return.  */
83       asm volatile("movab 1f, 16(fp)");
84
85     /* Return.  */
86     asm volatile("ret");
87   }
88
89   asm volatile("0:"     /* `rei' return.  */
90                /* Compensate for PSL-PC push.  */
91                "addl2 %0, sp;"
92                "1:"     /* Standard return.  */
93                /* Return to saved PC.  */
94                "jmp %1" : /* No outputs.  */ :
95                "g" (8), "g" (env.__pc));
96
97   /* Jump here when the FP saved in ENV points
98      to a function that has already returned.  */
99   asm volatile("latejump:");
100   __libc_fatal("longjmp: Attempt to jump to a function that has returned.\n");
101 }