[comp.arch] Aliasing, etc. in C

brandenberg@star.dec.com.UUCP (01/26/87)

[ From sun!gorodish!guy ]
> From [?]
>>God forbid, but there is probably some C program out there that relies
>>on being able to:
>>	int a,b, *ptr;
>>
>>	ptr = &a;
>>	ptr++;
>>	/* ptr now points to b */
> 
>No program that relies on that is correct C, so no compiler is
>obliged to make them work.  In fact, the sooner such programs *are*
>prevented, the better off we'll all be.

Oh?  If this is aberrant coding, you might want to look at your
varargs.h file whose operation relies on these assumptions; and this is
in the ANSI proposal.

					- Monty

-------------
Industry Standards:  Advancing computer engineering to the lowest common
denominator.

dce@mips.UUCP (01/26/87)

In article <7803@decwrl.DEC.COM> brandenberg@star.dec.com (bleakness...desolation...plastic forks...) writes:
>
>[ From sun!gorodish!guy ]
...
>>No program that relies on that [aliasing] is correct C, so no compiler is
>>obliged to make them work.  In fact, the sooner such programs *are*
>>prevented, the better off we'll all be.
>
>Oh?  If this is aberrant coding, you might want to look at your
>varargs.h file whose operation relies on these assumptions; and this is
>in the ANSI proposal.
>
>					- Monty

Hold on. What Guy says is that no compiler is "obliged" to make the
specifically given code work. The ANSI proposal requires that varargs.h
be implemented and that it aid in performing a certain function. It
does not say *how* variable number of arguments has to work.

In the Mips system, where the first 4 parameters to a subroutine are
passed in registers, the compiler actually keys on the word 'va_alist'
in the argument list to force the parameters to be copied onto the
stack. Because of this, you can actually do some very machine-dependent
code. For example, I've found cases where code like:

	error(code, fmt, args)
		int code;
		char *fmt;
		int args;
	{
		...
		_doprnt(fmt, &args, stderr);
		...
	}

was "ported" to our system by simply changing all instances of "args" to
"va_alist". This was done because the person doing the porting looked at
varargs.h and used system-dependent knowledge instead of using what the
definition says. The fact that "it works" doesn't make it legal, since
it doesn't use the "required" va_start() or va_end().

Basically, all the ANSI proposal says is that a conforming system has to
supply:

	a. varargs.h, which may even be effectively empty
	b. the items listed in varargs(3)

It makes no difference to the ANSI proposal whether va_alist is a macro,
a typedef, or a builtin type. It shouldn't matter to the code how the
arguments are stored or how va_arg() is implemented. Don't confuse requirements
for functionality with requirements for architectural conformity.
-- 
			David Elliott

UUCP: 	{decvax,ucbvax,ihnp4}!decwrl!mips!dce, DDD:  	408-720-1700

guy@gorodish.UUCP (01/26/87)

>Oh?  If this is aberrant coding, you might want to look at your
>varargs.h file whose operation relies on these assumptions; and this is
>in the ANSI proposal.

Sorry, but this just doesn't hold water.  The ONLY thing in the ANSI
proposal about "varargs" is that there is an include file <stdarg.h>
(NOT <varargs.h>!) and that when you include it certain things are
defined.  There is nothing whatsoever in the ANSI spec that requires
that the <varargs.h> distributed with most UNIX systems has to work;
in fact, there are implementations on which it DOESN'T work.
(Consider a machine with register windows, where the first N scalar
parameters are not placed in memory at all - or any other
implementation that passes parameters in registers.)  Those
implementations have to do something else to make it work.

There is nothing in the ANSI draft that says anything whatsoever
about where variables are placed in memory relative to one another -
or about whether variables whose address isn't taken need be in
memory at all!

radford@calgary.UUCP (01/27/87)

In article <7803@decwrl.DEC.COM>, brandenberg@star.dec.com (bleakness...desolation...plastic forks...) writes:

> >>	int a,b, *ptr;
> >>
> >>	ptr = &a;
> >>	ptr++;
> >>	/* ptr now points to b */
> > 
> >No program that relies on that is correct C...
> 
> Oh?  If this is aberrant coding, you might want to look at your
> varargs.h file whose operation relies on these assumptions; and this is
> in the ANSI proposal.

As I understand it, the ANSI proposal specifies that the FUNCTION of
varargs.h must exist, not that the particular varargs.h source file
you are looking at must work. Indeed, there would be no point in mentioning
varargs.h in the standard if the code it contained was guaranteed to
work on all machines.

    Radford Neal

cdshaw@alberta.UUCP (01/28/87)

This argument about pointer games should really be in comp.lang.c 
(or something).
Anyway, it's getting very stale here in comp.arch.
-- 
Chris Shaw    cdshaw@alberta
University of Alberta
CatchPhrase: Bogus as HELL !

chris@mimsy.UUCP (Chris Torek) (01/28/87)

Guy hardly needs defending, but it may sound better coming from two
people:

	/* this code is not portable */
	int a,b, *ptr;

	ptr = &a;
	ptr++;
	/* ptr now points to b */

>[ From sun!gorodish!guy ]
>>No program that relies on that is correct C, so no compiler is
>>obliged to make them work.

In article <7803@decwrl.DEC.COM> brandenberg@star.dec.com
(bleakness...desolation...plastic forks...) writes:
>Oh?  If this is aberrant coding, you might want to look at your
>varargs.h file whose operation relies on these assumptions; and this is
>in the ANSI proposal.

Wrong.  *Varargs* is in the ANSI proposal.  Neither the *Vax*
*implementation* nor the *Sun* *implementation* (each of which
works by peeking at stack addresses) is the ANSI proposal.  Nor is
Pyramid's implementation, which is considerably more complex and
does *not* rely upon `ptr = &a; ptr++;' pointing to `b' (which is
only sometimes the case).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!mimsy!chris	ARPA/CSNet:	chris@mimsy.umd.edu

jpn@teddy.UUCP (01/29/87)

>Oh?  If this is aberrant coding, you might want to look at your
>varargs.h file whose operation relies on these assumptions; and this is
>in the ANSI proposal.

Sigh....   Varargs is DEFINED as being machine-dependent - in other words,
those varargs macros/functions may have to be rewritten for every machine -
it is up to the system providers to provide definitions that work for a
SINGLE machine:  the one that is being compiled for.  Any user code that
does this is not portable.

>>>	int a,b, *ptr;
>>>
>>>	ptr = &a;
>>>	ptr++;
>>>	/* ptr now points to b */

Any program that is expected to work on more than one machine MUST NOT
make assumptions about memory layout.  This is the reason why varargs
exists:  So that 100's of programs do not have to make such assumptions!
Sure, this is legal C, but the trailing comment is NOT NECESSARILY TRUE!

guy@gorodish.UUCP (02/02/87)

>Nor is Pyramid's implementation, which is considerably more complex and
>does *not* rely upon `ptr = &a; ptr++;' pointing to `b' (which is
>only sometimes the case).

I presume this is because it's a register-window machine, and some
parameters may be passed in registers, so that not all of the
parameters are necessarily stored in memory?

This is one reason *why* the ANSI proposal can't just say "the
'conventional' implementation of 'varargs' has to work."  There may
be machines where you can't make it work!

hansen@mips.UUCP (02/03/87)

In article <12570@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes:
> >Nor is Pyramid's implementation, which is considerably more complex and
> >does *not* rely upon `ptr = &a; ptr++;' pointing to `b' (which is
> >only sometimes the case).
> 
> I presume this is because it's a register-window machine, and some
> parameters may be passed in registers, so that not all of the
> parameters are necessarily stored in memory?

The MIPS compiler, which passes four arguments in registers, will recognise
the use of the <varargs.h> constructs in the argument list and push the
registers back out to memory when required. This permits printf-line
routines to work, which is a more severe constraint than <varargs.h> itself,
as the argument list is normally passed onto routines such as _doprnt by the
address of the format string argument. It certainly makes porting code
easier than rewriting everything to use the formal varargs interface as
strictly defined, and for that I'm already grateful to our compiler team.
-- 

Craig Hansen			|	 "Evahthun' tastes
MIPS Computer Systems		|	 bettah when it
...decwrl!mips!hansen		|	 sits on a RISC"

csg@pyramid.UUCP (02/03/87)

>>Nor is Pyramid's implementation, which is considerably more complex and
>>does *not* rely upon `ptr = &a; ptr++;' pointing to `b' (which is
>>only sometimes the case).
>
>I presume this is because it's a register-window machine, and some
>parameters may be passed in registers, so that not all of the
>parameters are necessarily stored in memory?

Exactly. The first 12 scalar arguments are passed through the register window,
from left to right in registers pr0, pr1, pr2, etc. Structures (including one-
word structs) and args beyond the 12th are pushed on the stack in order from
right to left (VAX style). Doubles need two registers and are always aligned
on an 8-byte boundary (to prevent an argument from straddling the register
file and the stack). 

Since you can take the address of a register on the Pyramid, it is possible to
do a VAX style varargs so long as you don't try to pass structs or doubles, or
use more than 12 arguments. Like Chris said, "only sometimes the case."

If you try taking the address of local variables, which is where this silly
discussion started, you are totally hosed. The order of assignment in the
register file is picked by the compiler, based on the frequency of reference.
And if you declare "int a, b" and the references to them are isolated from
each other, they will likely end up being the same register. 

<csg>

ramin@scampi.UUCP (02/06/87)

In article <5230@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> Guy hardly needs defending, but it may sound better coming from two
> people:
> 
> 	/* this code is not portable */
> 	int a,b, *ptr;
> 
> 	ptr = &a;
> 	ptr++;
> 	/* ptr now points to b */
> 
I agree entirely...
In fact, I conducted a quick experiment on a Sun-3 system which resulted
in vastly different results depending on the location of the "int a,b, *ptr"
line:

	long	a,b,*ptr;	/* note: it's static */
	main()
	{
		a = 1; b = 2;
		ptr = &a;
		ptr++;
		*ptr = 3;
		printf("%08.8X %08.8X %08.8X\n",&a,&b,ptr);
		printf("%d %d %d\n",a,b,*ptr);
	}

which resulted in:

00020DBC 00020DC0 00020DC0
1 3 3

and also...

	main()
	{
	long	a,b,*ptr;	/* note: it's NOT static */
	
		a = 1; b = 2;
		ptr = &a;
		ptr++;
		*ptr = 3;
		printf("%08.8X %08.8X %08.8X\n",&a,&b,ptr);
		printf("%d %d %d\n",a,b,*ptr);
	}

which gave:

0EFFFE98 0EFFFE94 0EFFFE9C
1 2 3

Now obviously the second program is a *VERY* problematic one considering
the compiler put a and b on the stack in the reverse order.
As far as I'm concerned both are severely brain-damaged ways of coding.

But the original topic was slanted towards varargs (i.e.
AFTER having called something and the gripe against making assumptions
about doing the above to a call frame) and it got somewhat sidetracked
to discussions of proper C-coding. A utility supplied with a compiler
should be able to to make certain assumption about how the compiler
and the machine it is targeted at pass parameters back and forth.

For the mortals using the compiler to make such an assumption and maintain
portability is folly...

ramin

-- 

(insert-file ".disclaimers")

ramin firoozye'			{ihnp4,lll-lcc,hoptoad}!scampi!ramin
systems control inc.		(415) 494-1165 x-1777
1801 page mill road
palo alto, ca  94304
*** Wars are not fought to decide who is right... Only who is left... ***

wcs@ho95e.UUCP (02/08/87)

				[line-eater bait, included because]
				[2.11news wants some extra lines anyway]
In article <5230@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
>> Guy hardly needs defending, but it may sound better coming from two
>> people:
>> 	/* this code is not portable */
>> 	int a,b, *ptr;
>> 	ptr = &a;
>> 	ptr++;
>> 	/* ptr now points to b */

This code works especially well if your optimizing compiler puts b in a
register.  Even the proverbial lament "but it worked on my *VAX*" may
not apply here.
-- 
# Bill Stewart, AT&T Bell Labs 2G-202, Holmdel NJ 1-201-949-0705 ihnp4!ho95c!wcs