From: leichter@lrw.com (Jerry Leichter)
Newsgroups: comp.os.vms
Subject: Re: VAXC divide problems (V3.2)
Date: 28 Jan 93 03:41:13 GMT
Distribution: world
Organization: The Internet


	 >>Gruesome details are available in the CRTL portion of the VMS
	>>listings.  This ugly violation of the VMS Procedure Calling Standard

	> In what way is this a violation of the Procedure Calling Standard?
	> It is perfectly legitimate for a procedure to reserve space on the
	> stack for data of local interest; nothing says that that space has
	> to correspond to variables visible to the user.

	That won't wash.  The violation is in VAXC$ESTABLISH, which will
	clobber the top of your stack if you haven't allocated the
	undocumented hidden variable for it.  It mungs its _caller's_ stack;
	that's completely different from extra stack space being used by the
	current procedure.

	Alternatively, your own code can clobber the saved handler address,

Your own code cannot touch the saved handler address unless it uses and
invalid pointer.  It could just as easily clobber the handler address at
(FP).

	which in turn can result in an ACCVIO inside VAXCRTL for non-longjmp
	conditions.  The documentation for VAXC$ESTABLISH states that it is
	only usable from code compiled by VAX C because that particular
	compiler allocates stack space for its use, but it still violates the
	procedure calling standard.

It is perfectly legitimate for a procedure in a language support RTL to make
assumptions about the environment compiled code will set up for it.  Try
calling one of the routines that implements formatted I/O in FORTRAN without
setting up the appropriate environment.

LIB$ESTABLISH also modifies its caller's stack frame.  In fact, the only
difference between LIB$ESTABLISH and VAXC$ESTABLISH is in the addressing
mode of one instruction.  Do you also claim that LIB$ESTABLISH is in violation
of the Standard?

In many languages, you NEVER call language support RTL routines directly;
the compiler generates all the calls.  In C, because of its extreme low level,
just about all calls have to be visible to the user.

Calling internal FORTRAN support routines is not supported, except in code
generated by the FORTRAN compiler.  (That's not to say it can't be made to
work.)  Calling VAXC$ESTABLISH is not supported outside of code generated by
the VAX C compiler (although again it can be made to work).  I see no signi-
ficant difference, and I see no violation of the calling standard.  Would it
have made you happier if, instead of a documented VAXC$ESTABLISH routine,
VAX C had defined a new statement, say establish <handler>, which turned into
just such a call?

	>                      It is perfectly permissible for a condition
	> handler to make calls to other procedures, basing its choices on
	> locally available data. That's just what this condition handler is
	> doing; it's no different, in principle, from having a local variable
	> that indicates what you were trying to do, and a condition handler
	>  that checks that variable to decide what furtheraction to take.

	     That would be true if such usage didn't interfere with user code.
	Try calling VAXC$ESTABLISH from code compiled by some other compiler
	sometime (recent releases of GCC excepted), then tell me that it isn't
	violating the procedure calling standard.

Try calling the Ada RTL routines that manage tasking from some code written in
some other language.  In fact, I'll bet that if you name any language RTL, I
can find some routine in it that, if called from another language, will cause
quick failure.  So?

As for GCC:  It's really too damn bad for GCC that, when it tries to make use
of the VAX C RTL, it has to play by the rules.  The VAX C RTL was written to
support the VAX C compiler.  It owes absolutely nothing to the writers of
GCC.

	>>is for setjmp/longjmp handling, and is inherited from the Pascal
	>>compiler of all places! ...

	> Actually, I think it's the BASIC compiler (which had to pull the
	> same kind of trick to implement its user error handling).

	     My post was not based on speculation; check the source listings.
	They took the implementation from Pascal's GOTO handler.  Perhaps the
	Pascal implementation was derived from BASIC's, but if so, the C code
	doesn't mention it.

What can I tell you; my understanding was that the technique of using stack
unwinding as it is done in VAX C was first developed for BASIC.  Good
solutions to hard problems get re-used.  BASIC's needs are somewhat different,
so I can't say I'm shocked that the actual code came from Pascal.

Look, let's back off and look at the bigger picture for a moment.  The C
language brings with it two features - well, one is just a common abuse of
the language - that are in and of themselves incompatible with the VAX
Procedure Calling standard:

	1.  Functions view their arguments as a block of successive values
		which they can step through - and modify.  Without the
		overhead of copying values around, this results in generated
		code that modifies the values pointed to by AP, a practice
		once strictly prohibited by the Calling Standard:  That data
		belongs exclusively to the caller.  A field test version of
		VAX C (I think V3.0) tried to obey the calling standard
		strictly:  When the address of any argument was taken, the
		argument was re-bound to a new stack location, and the value
		passed in the argument block was copied on procedure entry.
		Such an implementation is completely consistent with both
		K&R and ANSI C, as well as with the Standard.  However, so
		many customers objected that it broke their code that the
		change was backed out before the final version of the compiler
		and never tried again.  Instead, VAX C was given a waiver
		from this requirement of the Standard.  It causes grief for
		mixed FORTRAN/C programs to this day.

	2.  setjmp/longjmp simply cannot be implemented strictly within the
		Calling Standard.  The old "just pop the stack pointer back
		to where it was" approach is absolutely a violation.

		Rather than bitch about the "horrible" way this is done, would
		you like to suggest an implementation that will (a) conform
		to the ANSI definition; (b) conform to the Procedure Calling
		Standard; (c) behave rationally in a mixed language environ-
		ment, where there may be stack frames for code created by
		several different compilers arbitrarily mixed on the stack
		between the frame where the longjmp takes place and the frame
		it will end up in?  If you can, I, for one, would be quite
		interested in seeing it.
							-- Jerry

Xref: sparky comp.os.vms:22230 vmsnet.tpu:618