[comp.sys.nsc.32k] Bug in minix library setjmp.s; lots of GNU tools diffs available

jkp@sauna.hut.fi (Jyrki Kuoppala) (02/06/91)

When porting emacs to pc532-Minix, I noticed there's a bug in the
setjmp library routine - it doesn't save registers r3-r7 (and f4-f7)
which I think it should do.  This seems like a serious bug and I'm
surprised it has caused so little trouble when compiling all the other
software I have on the pc532.

At the end of this message there's a fixed setjmp.s (it's in gas
format as I just moved to use GNU tools, but converting to Bruce
syntax shouldn't be difficult) and a test program to test the
functioning of setjmp.

I now have a complete environment (including libc) working with the
GNU tools: gcc 1.39 with patches, gas 1.38.1 with patches, GNU
binutils with patches, GNU make 3.59, emacs 18.57 (subprocesses don't
work yet), bash 1.05.1, GNU fileutils etc.  G++ will be easy now when
gas and GNU ld are used; gdb is next on my list.  Most of the diffs to
get these up are (or will be soon) available for anon. ftp from
nic.funet.fi in directory pub/misc/pc532/GNU-hut.  They're still not
very pretty to look at, but they work, mostly.  I think some programs
require kernel additions like some more support for flags of open(2)
and non-blocking I/O, fcntl flags etc.

Gas and binutils didn't cope with the ns32k family properly without
some fixing.  Bootstrapping with the broken Minix programs was also
painful.

If there's interest, I could perhaps make the binaries available (hmm,
I don't know what the various copyright restrictions with Minix and GNU
software have to say to that).

I'd like to scrap all the Minix library routines (except the syscalls,
of course - they'll have to wait until we get free Mach 3.0) for a
free libc.  Any good free library sources out there ?

Here's setjmp.s:

#APP
#
# jkp@cs.hut.fi added saving & restoring of r3-r7 & f4-f7 5 Feb 1991
sj_fp=0
sj_sp=4
sj_pc=8
sj_r3=12
sj_r4=16
sj_r5=20
sj_r6=24
sj_r7=28
sj_f4=32
sj_f5=36
sj_f6=40
sj_f7=44

	.text
.globl _setjmp
_setjmp:
	movd	4(sp),r0	#ptr to struct
	addr	0(fp),sj_fp(r0)	#save fp
	addr	0(sp),sj_sp(r0)	#save sp
	addr	0(r3),sj_r3(r0)	#save r3
	addr	0(r4),sj_r4(r0)	#save r4
	addr	0(r5),sj_r5(r0)	#save r5
	addr	0(r6),sj_r6(r0)	#save r6
	addr	0(r7),sj_r7(r0)	#save r7
	addr	0(f4),sj_f4(r0)	#save f4
	addr	0(f5),sj_f5(r0)	#save f5
	addr	0(f6),sj_f6(r0)	#save f6
	addr	0(f7),sj_f7(r0)	#save f7
	movd	0(sp),sj_pc(r0)	#save return address
	movqd	0,r0		#return 0
	ret	0

.globl _longjmp
_longjmp:
	movd	8(sp),r0	#return value
	cmpqd	0,r0		#never return 0
	bne	longjmp1
	movqd	1,r0
longjmp1:
	movd	4(sp),r1	#pointer to env
	movd	sj_f7(r1),f7	#restore f7
	movd	sj_f6(r1),f6	#restore f6
	movd	sj_f5(r1),f5	#restore f5
	movd	sj_f4(r1),f4	#restore f4
	movd	sj_r7(r1),r7	#restore r7
	movd	sj_r6(r1),r6	#restore r6
	movd	sj_r5(r1),r5	#restore r5
	movd	sj_r4(r1),r4	#restore r4
	movd	sj_r3(r1),r3	#restore r3
	lprd	sp,sj_sp(r1)	#restore sp
	lprd	fp,sj_fp(r1)	#restore fp
	movd	sj_pc(r1),0(sp)	#restore return adr
	ret	0

Remember to change _JBLEN from 3 to 12 in /usr/include/setjmp.h

Here's the test program:

#include <stdio.h>
#include <setjmp.h>

jmp_buf env;
void foo()
{
	register int b = 2;
	fprintf (stderr, "b = %d\n", b);
}

void bar()
{
	register int c = 3;
	fprintf (stderr, "c = %d\n", 3);
	longjmp(env, 1);
}

main()
{
	register int a = 1;
	foo();
	if (setjmp (env))
		fprintf (stderr, "a = %d\n", a);
	else {
		bar();
	}
}

It outputs:

b = 2
c = 3
a = 1

when everything is OK, but

b = 2
c = 3
a = 3

when the bug exists.

//Jyrki

ian@sibyl.eleceng.ua.oz.au (02/07/91)

Jyrki Kuoppala writes:
 - When porting emacs to pc532-Minix, I noticed there's a bug in the
 - setjmp library routine - it doesn't save registers r3-r7 (and f4-f7)
 - which I think it should do.
 - Here's the test program:
 - 
 - #include <stdio.h>
 - #include <setjmp.h>
 - 
 - jmp_buf env;
 - void foo()
 - {
 - 	register int b = 2;
 - 	fprintf (stderr, "b = %d\n", b);
 - }
 - 
 - void bar()
 - {
 - 	register int c = 3;
 - 	fprintf (stderr, "c = %d\n", 3);
 - 	longjmp(env, 1);
 - }
 - 
 - main()
 - {
 - 	register int a = 1;
 - 	foo();
 - 	if (setjmp (env))
 - 		fprintf (stderr, "a = %d\n", a);
 - 	else {
 - 		bar();
 - 	}
 - }
 - 
 - It outputs:
 - 
 - b = 2
 - c = 3
 - a = 1
 - 
 - when everything is OK, but
 - 
 - b = 2
 - c = 3
 - a = 3

I believe in ANSI C, there is no requirement to save registers in setjump.
Variables which have to be accessed after the setjump should be marked
volatile. Yes, some people have said that is ugly and nor the way it
should be done, but I pretty sure, that is the way it is!

Ian

news@daver.bungi.com (02/08/91)

Ian writes:
>Jyrki Kuoppala writes:
> - When porting emacs to pc532-Minix, I noticed there's a bug in the
> - setjmp library routine - it doesn't save registers r3-r7 (and f4-f7)
> - which I think it should do.
...
>I believe in ANSI C, there is no requirement to save registers in setjump.
>Variables which have to be accessed after the setjump should be marked
>volatile. Yes, some people have said that is ugly and nor the way it
>should be done, but I pretty sure, that is the way it is!

I write: Ian is correct.  Nevertheless all of the following compilers
produce the result that Jyrki K's claims is correct:

	Gcc on 386
	Gcc on Sun-3 (68020)
	Cc on 386 (pcc based)
	Cc on Sun (probably pcc based)
	Microsoft C (claims to be ANSI compatible)

So it seems that's the way it isn't.

I suspect that register variables ought to be preserved despite what the
ANSI standard says, particularly since well optimized C compilers put
everything they can into registers whether or not they are declared
register.

Jonathan Ryshpan		<...!uunet!hitachi!jon>

news@bungi.com.YorkU.CA (02/08/91)

> 
> Jyrki Kuoppala writes:
>  - When porting emacs to pc532-Minix, I noticed there's a bug in the
>  - setjmp library routine - it doesn't save registers r3-r7 (and f4-f7)
>  - which I think it should do.
[stuff deleted]

Ian write:
> I believe in ANSI C, there is no requirement to save registers in setjump.
> Variables which have to be accessed after the setjump should be marked
> volatile. Yes, some people have said that is ugly and nor the way it
> should be done, but I pretty sure, that is the way it is!

Some time back I ran into this setjump issue while trying to make all 
the 1.5.10 /usr/src/test programs run successfully.  In a nutshell I 
decided to set ANSI C aside and save all registers.  The essence of the 
decision was (1) that I have yet to run across a situation were saving 
all registers creates an adverse consequence (thats not to say they do 
not exist), (2) on numerious occasions not saving the registers has 
caused me a problem, and (3) in the large, the overhead of saving all 
registers is minimal.  

You might say I decided to switch rather than fight.  Alternatively, it 
might be argued that I put off the problem for someone else to solve.  
Never the less, this is one instance where I do not see the merit of 
strict ANSI C conformance.

My reading of ANSI C is that saving all registers is not in itself
a violation of the standard.  Rather that the consequence of doing so
may on occasion lead to unknowingly writing non-portable code (ie. code
that in someway depends upon setjmp saving all registers).

Considering that the setjump issue is a problem that we all share,
perhaps it would be useful for all of us to adopt a common solution.
That is, we collectively agree to (a) save all registers, or (b) 
actively go on a bug hunt :-).  Otherwise, this problem will 
continue to be a source of frustration, wasted time, generate message
traffic, etc.

Any thoughts pro or con ??

Obviously, my vote is for ignoring ANSI C and saving all registers --
that is unless someone makes a good case against.   


johnc

-- 
John Connin: manatee Orlando, Florida
         UUCP: {uunet,ge-dab,ucf-cs}!tarpit!tous!manatee!johnc

mea@mea.utu.fi (Matti Aarnio) (02/08/91)

Ian writes:
>Jyrki Kuoppala (jkp) writes:
> - When porting emacs to pc532-Minix, I noticed there's a bug in the
> - setjmp library routine - it doesn't save registers r3-r7 (and f4-f7)
> - which I think it should do.
...
>I believe in ANSI C, there is no requirement to save registers in setjump.
>Variables which have to be accessed after the setjump should be marked
>volatile. Yes, some people have said that is ugly and nor the way it
>should be done, but I pretty sure, that is the way it is!

  Actually GCC document quite EXPLICITELY tell you to make sure that
variables needing to be preserved across setjump()/longjump() MUST NOT
STAY IN REGISTERS.

  A way to force GCC to do this (normally GCC just ignores register
keyword and uses own heuristics!) is to take address of variable.
Even though that address might not be used, and simplest optimation
will drop instructions for it, this is the way:

   foo()
   {
	int a,b,c;	/* Have potential to get into registers		*/

	&b;		/* Make sure GCC won't let it stay in register.	*/
			/* Across func calls at least.			*/

	do your jumps
   }


  But of course you knew it, didn't you ?  JKP especially.

	/Matti Aarnio <mea@utu.fi> <mea@nic.funet.fi>

jkp@sauna.hut.fi (Jyrki Kuoppala) (02/09/91)

>Considering that the setjump issue is a problem that we all share,
>perhaps it would be useful for all of us to adopt a common solution.
>That is, we collectively agree to (a) save all registers, or (b) 
>actively go on a bug hunt :-).  Otherwise, this problem will 
>continue to be a source of frustration, wasted time, generate message
>traffic, etc.
>

Umm, actually I save only the registers that are not allowed to be
clobbered by the gcc calling convention - is there a reason to save
them all (other than someone using -fcall-saved-regs or changing the
convention) ?

//Jyrki

culberts@hplwbc.hpl.hp.com (Bruce Culbertson) (02/09/91)

> Jyrki Kuoppala (jkp) writes:

> When porting emacs to pc532-Minix, I noticed there's a bug in the
> setjmp library routine - it doesn't save registers r3-r7 (and f4-f7)
> which I think it should do.  This seems like a serious bug and I'm
> surprised it has caused so little trouble when compiling all the other
> software I have on the pc532.

I have read the various man pages for BSD, SysV, etc. and I think my
setjmp/longjmp actually conforms to the functionality it is required to
support.  However, I agree with Jyrki completely -- many programs we all
know and love incorrectly expect more from setjmp/longjmp and it is a
real pain if setjmp/longjmp does not preserve as much of the environment
as possible.  I have already made similar changes to the setjmp/longjmp
in the soon-to-be released 1.3/1.5 hybrid pc532-Minix.

> I now have a complete environment (including libc) working with the
> GNU tools: gcc 1.39 with patches, gas 1.38.1 with patches, GNU
> binutils with patches, GNU make 3.59, emacs 18.57 (subprocesses don't
> work yet), bash 1.05.1, GNU fileutils etc. ...

Great!  This is a really nice contribution.

> Bootstrapping with the broken Minix programs was also painful.

May I request that people not make vague negative comments like this.
What features of what programs are broken?  An OS and C implementation
are not broken just because they cannot compile and support all the
GNU programs.  I will attempt to fix bugs if I know what they are.

> 	addr	0(f4),sj_f4(r0)	#save f4
>	addr	0(f5),sj_f5(r0)	#save f5
>	addr	0(f6),sj_f6(r0)	#save f6
>	addr	0(f7),sj_f7(r0)	#save f7

I these are illegal instructions.  If you look at the instruction
encoding, you will see that there is no way to specify an addressing
mode like "0(f4)".  If gas does not catch this, it probably encodes
it as "0(r4)", which is not what you want.  The following should work:

 	movf	f4,sj_f4(r0)	#save f4
	movf	f5,sj_f5(r0)	#save f5
	movf	f6,sj_f6(r0)	#save f6
	movf	f7,sj_f7(r0)	#save f7

Cheers,
Bruce Culbertson

jkp@sauna.hut.fi (Jyrki Kuoppala) (02/09/91)

Bruce writes:
>> Bootstrapping with the broken Minix programs was also painful.
>
>May I request that people not make vague negative comments like this.
>What features of what programs are broken?  An OS and C implementation
>are not broken just because they cannot compile and support all the
>GNU programs.  I will attempt to fix bugs if I know what they are.

I haven't found anything that wrong in the C or library implementation
(except the setjmp problem).

It's just that the /bin/sh functionality is not quite what the various
configuration and installation scripts expect, the same goes for the
make program (it fails to make gcc, for example).  Also ls did
something very strange, and also various other programs I don't
remember which I've now replaced with GNU or other free stuff.

Sorry, I haven't put any effort to finding out what the bugs exactly
are since I'm trying to use the Minix programs as little as possible
to use as free a system as possible.

>>	addr	0(f7),sj_f7(r0)	#save f7
...

>I these are illegal instructions.

OK, thanks, I'll fix them - I never did study the ns32k assembler ;-)

//Jyrki

tim@proton.amd.com (Tim Olson) (02/12/91)

In article <9102072159.AA02808@halsoft>  writes:
| Ian writes:
| >Jyrki Kuoppala writes:
| > - When porting emacs to pc532-Minix, I noticed there's a bug in the
| > - setjmp library routine - it doesn't save registers r3-r7 (and f4-f7)
| > - which I think it should do.
| ...
| >I believe in ANSI C, there is no requirement to save registers in setjump.
| >Variables which have to be accessed after the setjump should be marked
| >volatile. Yes, some people have said that is ugly and nor the way it
| >should be done, but I pretty sure, that is the way it is!
| 
| I suspect that register variables ought to be preserved despite what the
| ANSI standard says, particularly since well optimized C compilers put
| everything they can into registers whether or not they are declared
| register.

Actually, the most "correct" implementation of setjmp/longjmp is to
ensure that all automatic variables, like statics and externals, have
the value they had at the time of the longjmp.  Saving register values
in the jmpbuf causes those that were actually in registers to have the
values they had at the time of the setjmp (but externals and
automatics not in registers have their longjmp value).  The reason the
ANSI standard specified that the values of non-volatile automatics are
not to be relied upon (how's that for a double-negative! ;-) is that:

	1) There exist "correct" implementations (VAX with
	   stack-unwind longjmp, register-windowed RISC processors).

	2) There exist "register save" implementations.

	3) Forcing one or the other to be the standard would be
	   prohibitive on various architectures.


--
	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)