summaryrefslogtreecommitdiff
path: root/sysdeps/vax/__longjmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/vax/__longjmp.c')
-rw-r--r--sysdeps/vax/__longjmp.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/sysdeps/vax/__longjmp.c b/sysdeps/vax/__longjmp.c
new file mode 100644
index 0000000000..0ee040ab25
--- /dev/null
+++ b/sysdeps/vax/__longjmp.c
@@ -0,0 +1,100 @@
+/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc.
+ Derived from @(#)_setjmp.s 5.7 (Berkeley) 6/27/88,
+ Copyright (c) 1980 Regents of the University of California.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <ansidecl.h>
+#include <setjmp.h>
+
+#ifndef __GNUC__
+ #error This file uses GNU C extensions; you must compile with GCC.
+#endif
+
+
+#define REI 02 /* Vax `rei' opcode. */
+
+/* Jump to the position specified by ENV, causing the
+ setjmp call there to return VAL, or 1 if VAL is 0. */
+__NORETURN
+void
+DEFUN(__longjmp, (env, val), CONST __jmp_buf env AND int val)
+{
+ register long int *fp asm("fp");
+ long int *regsave;
+ unsigned long int flags;
+
+ if (env.__fp == NULL)
+ __libc_fatal("longjmp: Invalid ENV argument.\n");
+
+ if (val == 0)
+ val = 1;
+
+ asm volatile("loop:");
+
+ flags = *(long int *) (6 + (char *) fp);
+ regsave = (long int *) (20 + (char *) fp);
+ if (flags & 1)
+ /* R0 was saved by the caller.
+ Store VAL where it will be restored from. */
+ *regsave++ = val;
+ if (flags & 2)
+ /* R1 was saved by the caller.
+ Store ENV where it will be restored from. */
+ *regsave = env;
+
+ /* Was the FP saved in the last call the same one in ENV? */
+ asm volatile("cmpl %0, 12(fp);"
+ /* Yes, return to it. */
+ "beql done;"
+ /* The FP in ENV is less than the one saved in the last call.
+ This means we have already returned from the function that
+ called `setjmp' with ENV! */
+ "blssu latejump;" : /* No outputs. */ : "g" (env.__fp));
+
+ /* We are more than one level below the state in ENV.
+ Return to where we will pop another stack frame. */
+ asm volatile("movl $loop, 16(fp);"
+ "ret");
+
+ asm volatile("done:");
+ {
+ char return_insn asm("*16(fp)");
+ if (return_insn == REI)
+ /* We're returning with an `rei' instruction.
+ Do a return with PSL-PC pop. */
+ asm volatile("movab 0f, 16(fp)");
+ else
+ /* Do a standard return. */
+ asm volatile("movab 1f, 16(fp)");
+
+ /* Return. */
+ asm volatile("ret");
+ }
+
+ asm volatile("0:" /* `rei' return. */
+ /* Compensate for PSL-PC push. */
+ "addl2 %0, sp;"
+ "1:" /* Standard return. */
+ /* Return to saved PC. */
+ "jmp %1" : /* No outputs. */ :
+ "g" (8), "g" (env.__pc));
+
+ /* Jump here when the FP saved in ENV points
+ to a function that has already returned. */
+ asm volatile("latejump:");
+ __libc_fatal("longjmp: Attempt to jump to a function that has returned.\n");
+}