jkp@cs.HUT.FI (Jyrki Kuoppala) (03/11/91)
As distributed, Minix (1.5.10 and I think also 1.3) setjmp library
routine doesn't save the registers which are not allowed to be
clobbered by the called function. Generally, Unix saves all registers
in setjmp. In my opinion, both of these methods seem to be about as
good, also there are some points to support the Minix style.
However, the compiler must be aware of when setjmp is called and must
generate code to save the registers which are not allowed to be
clobbered by the function. Otherwise trouble is on the way. This
kept me puzzled for a long time when I was porting emacs 18.57 to the
pc532, and didn't yet have a working debugger.
This diff makes gcc work right on those machines where the library
routine `setjmp' doesn't save registers and `longjmp' doesn't do stack
unwinding. Normally on these machines / environments code using
`setjmp' fails if compiled with gcc, because call-saved registers are
not saved in the function calling `setjmp' if they are not used. But
they might be used in functions called from the function calling
`setjmp' - the trouble is they never get restored when longjmp is
called.
This problem seems to exist at least on Minix, where the normal
`setjmp' library function doesn't save the registers. There is no
problem with the normal Minix compilers (I think), because they (I'm
told at least ACK and Bruce Evans's bcc) save all regs in the prologue
of a function calling `setjmp'.
There really is no requirement to save all the registers in `setjmp'.
The tradition in Unix seems to be that all registers are saved - I'm
told that in BSD this might be because partly the same mechanism is
used for handling signals and handling `setjmp'. Of course in signal
handling it's a must to save all the registers.
There's no big difference to do it either way. Perhaps to do it with
a `setjmp' not saving registers is a bit more efficient, because then
some registers don't have to be saved twice (first in the function
prologue for those used in the function, then all registers in
`setjmp'). If `setjmp' is called several times in a function,
non-reg-saving `setjmp' is also a win.
This modification requires reliable detection of `setjmp' by gcc.
This is possible to do, because ANSI says that `setjmp' is a macro
defined in <setjmp.h>. So `setjmp' can never be called via a pointer.
Gcc currently (as of version 1.39) detects calls to `setjmp' by
examining if the function called is named "setjmp" or "_setjmp" (see
expr.c). If `setjmp' is defined differently in your <setjmp.h>, you
have to modify either the definition or gcc to make the detection
work.
To tell gcc that your setjmp does not save all regs, add the line:
#define NON_REG_SAVING_SETJMP
to your tm.h file.
I have submitted this patch to gcc maintainers, so it might be
included in a future gcc release if considered useful. This should be
target machine-independent, but any bug reports are welcome.
*** orig/final.c Mon Aug 6 22:12:00 1990
--- final.c Mon Mar 4 21:15:05 1991
***************
*** 42,71 ****
--- 42,74 ----
The code for the function prologue and epilogue are generated
directly as assembler code by the macros FUNCTION_PROLOGUE and
FUNCTION_EPILOGUE. Those instructions never exist as rtl. */
#include <stdio.h>
#include "config.h"
#include "rtl.h"
#include "regs.h"
#include "insn-config.h"
#include "recog.h"
#include "conditions.h"
#include "gdbfiles.h"
#include "flags.h"
#include "real.h"
#include "output.h"
+ #ifdef NON_REG_SAVING_SETJMP
+ #include "hard-reg-set.h"
+ #endif
/* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */
#ifdef DBX_DEBUGGING_INFO
#ifdef USG
#include "stab.h" /* If doing DBX on sysV, use our own stab.h. */
#else
#include <stab.h> /* On BSD, use the system's stab.h. */
#endif /* not USG */
#endif /* DBX_DEBUGGING_INFO */
/* .stabd code for line number. */
#ifndef N_SLINE
#define N_SLINE 0x44
#endif
***************
*** 361,390 ****
--- 364,404 ----
FILE is the file to write assembler code to.
WRITE_SYMBOLS says which kind of debugging info to write (or none).
OPTIMIZE is nonzero if we should eliminate redundant
test and compare insns. */
void
final_start_function (first, file, write_symbols, optimize)
rtx first;
FILE *file;
enum debugger write_symbols;
int optimize;
{
block_depth = 0;
this_is_asm_operands = 0;
+
+ #ifdef NON_REG_SAVING_SETJMP
+ if (current_function_calls_setjmp)
+ {
+ int i;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (!call_used_regs[i] && !call_fixed_regs[i])
+ regs_ever_live[i] = 1;
+ }
+ #endif
/* Record beginning of the symbol-block that's the entire function. */
if (write_symbols == GDB_DEBUG)
{
pending_blocks[block_depth++] = next_block_index;
fprintf (file, "\t.gdbbeg %d\n", next_block_index++);
}
/* Initial line number is supposed to be output
before the function's prologue and label
so that the function's address will not appear to be
in the last statement of the preceding function. */
if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
{
--
Jyrki Kuoppala Helsinki University of Technology, Finland.
Internet : jkp@cs.hut.fi [130.233.251.253]
X400 : /C=fi/A=fumail/P=inet/O=hut/OU=cs/S=Kuoppala/G=Jyrki
BITNET : jkp@fingate.bitnet Gravity is a myth, the Earth sucks!
HBO043%DJUKFA11.BITNET@cunyvm.cuny.edu (Christoph van Wuellen) (03/11/91)
The problem is not a 'faulty' compiler, but setjmp/longjmp is a real mess. Declare everthing 'volatile' in functions fiddling with setjmp/longjmp. This might perhaps cure the problem. C.v.W.
ladd@cbnewsc.att.com (david.ladd) (03/13/91)
In article <1991Mar10.223859.380@santra.uucp> jkp@cs.HUT.FI (Jyrki Kuoppala) writes: >As distributed, Minix (1.5.10 and I think also 1.3) setjmp library >routine doesn't save the registers which are not allowed to be >clobbered by the called function. Generally, Unix saves all registers >in setjmp. In my opinion, both of these methods seem to be about as >good, also there are some points to support the Minix style. > >However, the compiler must be aware of when setjmp is called and must >generate code to save the registers which are not allowed to be I quote from the gcc.info file: `-traditional' Attempt to support some aspects of traditional C compilers. Specifically: .... * All automatic variables not declared `register' are preserved by `longjmp'. Ordinarily, GNU C follows ANSI C: automatic variables not declared `volatile' may be clobbered. To me, this suggests you either make everything volatile or use gcc -traditional. What's the big deal?
jkp@cs.HUT.FI (Jyrki Kuoppala) (03/14/91)
>To me, this suggests you either make everything volatile or use >gcc -traditional. What's the big deal? Aaaaarrrgggghhh. I would suggest that people read an article before they reply to it like this. I thought I was very verbose enough about explaining the problem now, learned on an earlier forum that people don't appear to think before they jump into conclusions. Seems that explaining things doesn't help. Ah well. Local variables are not the issue here, and -traditional does not cure the problem I was having. Someone also suggested that I should not blame a compiler when setjmp is faulty. I don't think I did blame a compiler, and to me it seems neither one (gcc or setjmp) is faulty, they just don't act well together. Minix setjmp takes a different approach than setjmp on Unix systems traditionally, and gcc as is doesn't have the functionality to handle this. I assume ACK and other Minix compiler do have the functionality to take care no registers are presumed valid when longjmp returns, so on Minix setjmp should work just fine along the ANSI spec. Haven't checked with ACK or other Minix compilers, though, 'cause I don't have them. But to make this flame perhaps useful for someone, the patch I sent doesn't cure all the problems - it only makes sure the function calling setjmp doesn't clobber the parent function's variables. To make local variables safe (I hear ANSI says that they are guaranteed to remain valid if they are not modified between setjmp and longjmp) you'll need to put local variables in stack in functions calling setjmp on OS's like Minix where setjmp doesn't save registers. There might still be a problem with gcc storing something (like a function address) in call-saved registers and assuming it to be there when setjmp returns. But this problem would appear also on machines where longjump restores registers from stack instead of the jump buffer, and there seems to be code in flow.c to take care of this. Here's a diff for that which should fix local variables handling, although I haven't tested it it should be simple enought so that no bugs have crept in. *** c-decl.c.orig Tue Mar 12 01:22:03 1991 --- c-decl.c Tue Mar 12 01:25:59 1991 *************** *** 4757,4768 **** /* Must mark the RESULT_DECL as being in this function. */ DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; ! /* Obey `register' declarations if `setjmp' is called in this fn. */ ! if (flag_traditional && current_function_calls_setjmp) { setjmp_protect (DECL_INITIAL (fndecl)); setjmp_protect_args (); } --- 4757,4774 ---- /* Must mark the RESULT_DECL as being in this function. */ DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; ! /* Obey `register' declarations if `setjmp' is called in this fn. ! if ( ! #ifndef NON_REG_SAVING_SETJMP ! /* If setjmp doesn't save registers, we'll have to put all local ! variables in the stack whether -traditional or not */ ! flag_traditional && ! #endif ! current_function_calls_setjmp) { setjmp_protect (DECL_INITIAL (fndecl)); setjmp_protect_args (); } *** function.c.orig Tue Mar 12 01:31:54 1991 --- function.c Tue Mar 12 01:34:59 1991 *************** *** 2877,2887 **** for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) && DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == REG ! && ! TREE_REGDECL (decl)) put_var_into_stack (decl); for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) setjmp_protect (sub); } --- 2877,2893 ---- for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) && DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == REG ! #ifndef NON_REG_SAVING_SETJMP ! /* To make variables not clobbered on machines where setjmp ! doesn't save registers, we'll have to put also those declared ! as `register' in the stack. */ ! && ! TREE_REGDECL (decl) ! #endif ! ) put_var_into_stack (decl); for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) setjmp_protect (sub); } *************** *** 2895,2905 **** decl; decl = TREE_CHAIN (decl)) if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) && DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == REG ! && ! TREE_REGDECL (decl)) put_var_into_stack (decl); } /* Return the context-pointer register corresponding to DECL, or 0 if it does not need one. */ --- 2901,2914 ---- decl; decl = TREE_CHAIN (decl)) if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) && DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == REG ! #ifndef NON_REG_SAVING_SETJMP ! && ! TREE_REGDECL (decl) ! #endif ! ) put_var_into_stack (decl); } /* Return the context-pointer register corresponding to DECL, or 0 if it does not need one. */ //Jyrki
richard@aiai.ed.ac.uk (Richard Tobin) (03/14/91)
In article <1991Mar12.225635.29426@cbnewsc.att.com> ladd@cbnewsc.att.com (david.ladd) writes: > * All automatic variables not declared `register' are > preserved by `longjmp'. Ordinarily, GNU C follows ANSI C: > automatic variables not declared `volatile' may be clobbered. This has nothing to do with the problem. If "-traditional" is set, in a function that calls setjmp(), gcc only puts into registers those variables declared "register". Normally, it ignores register declarations and puts whatever variables it feels like in registers. The real problem is that the Minix setjmp() only saves those registers that the Minix compiler needs saved. If you use gcc, you need a setjmp() that saves the registers that gcc needs saved. The simplest solution is to save all the registers. This means that setjmp() is good for all compilers (and for assembler too). -- Richard -- Richard Tobin, JANET: R.Tobin@uk.ac.ed AI Applications Institute, ARPA: R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin