[net.unix-wizards] varargs

greg@vecpyr.UUCP (Greg Millar) (04/11/86)

I have always heard that varargs is not very portable.  Is this really
true?  If you know of any machine that is running 4.X BSD, System III/V,
Xenix or any other real unix that doesn't support varargs, please let
me know.

Under AIX there are 3 functions associated with varargs called:
vsprintf, vprintf, vfprintf.  Are these only available on the IBM RT PC?

		
			Greg Millar

			...{ucbvax,decwrl}!dual!vecpyr!greg
			Visual Engineering, Inc.  
			2680 N. First
			San Jose, CA 95134
			(408) 945-9055

grr@cbmvax.cbm.UUCP (George Robbins) (04/12/86)

In article <272@vecpyr.UUCP> greg@vecpyr.UUCP (Greg Millar) writes:
>I have always heard that varargs is not very portable.  Is this really
>true?  If you know of any machine that is running 4.X BSD, System III/V,
>Xenix or any other real unix that doesn't support varargs, please let
>me know.
>
>Under AIX there are 3 functions associated with varargs called:
>vsprintf, vprintf, vfprintf.  Are these only available on the IBM RT PC?
>
>	Greg Millar {ucbvax,decwrl}!dual!vecpyr!greg
>	Visual Engineering, Inc. 2680 N. First San Jose, CA 95134

You have to define precisly what you mean by varargs...

The strict/slimey definition that works on many/most unix systems is that a
*C* function can index through its argument list in a linear fashion by taking
the address of the first argument and incrementing by the length of each
argument (which you must know or be told).  This assumes that the arguments
are all stored in some contiguous, rational order on the stack or in some
parameter block.  It is also generally assumed that a function can pass its
arguments to a function it calls, without knowing anything about them.
(frequent example: debug functions whose arguments are passed to printf)

Since these conventions are known not to work on all machines, it was decided
to create a set of 'magical' varargs routines that would allow a C program
to access it's arguments in a machine independent way.  Supposedly the
vprintf, etc. routines are reimplementations of printf, etc. that make use
of the these machine independent varargs conventions.

As you might expect, implementations where strict/slimey varargs works on the
hardware people tend to be careless about implementing/using the machine
independent form, and people who are stuck with implementations that require
the machine independent form tend to be kind of bitter about 'portable' code
created using the strict/slimey conventions.

-- 
George Robbins - now working with,	uucp: {ihnp4|seismo|caip}!cbmvax!grr
but no way officially representing	arpa: cbmvax!grr@seismo.css.GOV
Commodore, Engineering Department	fone: 215-431-9255 (only by moonlite)

ark@alice.UucP (Andrew Koenig) (04/13/86)

> I have always heard that varargs is not very portable.  Is this really
> true?  If you know of any machine that is running 4.X BSD, System III/V,
> Xenix or any other real unix that doesn't support varargs, please let
> me know.

> Under AIX there are 3 functions associated with varargs called:
> vsprintf, vprintf, vfprintf.  Are these only available on the IBM RT PC?

I am the author of varargs.

If you find any machine with a sensible architecture that cannot
be made to support varargs, I would greatly like to hear about it.

I also wrote the v*printf functions.  As far as I know, they are
a standard part of System V.

kalash@ingres.berkeley.edu.ARPA (Joe Kalash) (04/18/86)

>Under AIX there are 3 functions associated with varargs called:
>vsprintf, vprintf, vfprintf.  Are these only available on the IBM RT PC?
>

	These functions are available under any system that conforms
to the SVID.


			Joe Kalash
			kalash@berkeley
			ucbvax!kalash

rb@ccird2.UUCP (Rex Ballard) (04/25/86)

In article <5302@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes:
>> I have always heard that varargs is not very portable.  Is this really
>> true?  If you know of any machine that is running 4.X BSD, System III/V,
>> Xenix or any other real unix that doesn't support varargs, please let
>> me know.
>
>If you find any machine with a sensible architecture that cannot
>be made to support varargs, I would greatly like to hear about it.
>
The concern about about varargs is brought up in "Software Tools" by
Kernigan and Plauger.  The main concern is that certain systems and
languages have the caller push the arguments, and have the callee destroy
them when they are finished.  This is common practice in Fortran and
Pascal.  The big concern with C is that there might be a compiler out
there which has C/Pascal|Fortran compatibility.  Since these compilers
seem to be the exception rather than the rule, and newer versions of
these languages are tending to follow C conventions, this is not likely
to be a problem for *most* environments.

I have heard that there are a few "peculiar"
compilers available for the Atari ST, Mac, and Amiga, which, although
not "kosher", CAN support most varargs situations.  The problems that
can occur are "intelligent" compilers which put arguments directly
into registers rather than on the stack.  Appearantly, this can be
a real problem if you wish to "intercept" a system call at the
application side.  Why do so many of the micro operating systems
insist on putting arguments in registers!!!.  Even MS-DOS expects
arguments in registers rather than on the stack.

The C frame is a more sensible archetecture, but not the only one.
Since you specifically asked about UNIX based systems, you can be
relatively unconcerned.

There are non-portable ways to USE varargs.  The classic is to put
a long indicator into the "format argument" and pass an int. Do this
with a couple of arguments where ints are 16 bits, and longs are 32 bits,
and you will return to "never never land".  The normal usages
(printf, scanf,...) aren't usually a problem, but there are a few
"mix and match" functions using varargs which selectively mix and match
various modifiable stack addresses, and will "core dump" the whole
system.

try this: (comments are for 16 bit ints, 32 bit longs, 32 bit pointers).

main()
{
    /* top of frame = return address */
    int i;
    long l;
    scanf("%d %d",&i);	/* second argument missing, clobbers frame */
    scanf("%d",i);	/* cute "poke" of i, can demolish code or core dump */
    scanf("%ld",&i);	/* extra 16 bits is usually frame pointer or return
			   address */
    scanf("%d",l);	/* 16 bits of "garbage" plus your number possibly
			   munged beyond recognition due to byte ordering */
}

Lint will pass it, assuming printf is declared /*VARARGS*/, and the
compiler won't even sneeze.  But running it will give you "buss error
core dumped" or something equally nasty.  This is one of the few areas
where lint will not protect you.

Anyone figured out a syntax checker for these functions?
Of course, you should use a syntax checker for any of these functions.

Another cute trick I've seen is using varargs to pass integers to
functions which assign to pointers. Such as:

main()
{
    int read();
    init(0x20L,&read);	/* set exception vector */
}

/*VARARGS*/
init(a,b)
char **a,*b,**i;
{
	*a=b;	/* poke absolute value with a valid address */
}

This is the ultimate in unportability, but is frequently "hidden" in
"hostile" PC programs, typically to mount new device drivers and
remove them when the code is complete.  Just try plugging one of these
into unix unmodified :-).

eric@chronon.UUCP (Eric Black) (05/01/86)

In article <129@drilex.UUCP> dricej@drilex.UUCP writes:
>
>rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to
>handle varargs. ...
>... Therefore, a more proper question would be: is there any
>architecture which is suitable for a C compiler, but not for varargs?

Yes!  I can think of an example close to home... An architecture with
a large (LARGE) number of registers, a sliding window to allow reference
to a smaller register set locally within a procedure, and OS support
for using the register set as a stack (handling overflow/underflow).
The first <n> arguments are passed in registers via the overlapped
sliding window, remaining have to be passed in memory.  The problem
is that no choice of <n> will be correct; you can only make arbitrarily
small the probability of it not being big enough...  and at the cost of
additional expense elsewhere...
I assert that this architecture, and the rest of what goes with this
particular feature, is particularly well-suited for efficient execution
of programs written in C.

>P.S. Microcomputers pass things in registers, rather than on the stack,
>because stack operations are slow relative to register operations.  This
>is also typical of assembly language programming, rather than C language
>programming.
>Not everybody is willing to pay the high-level language penalty.
>
>Craig Jackson
>UUCP: {harvard,linus}!axiom!drilex!dricej

Microcomputers aren't the only ones interested in the fact that using
registers is faster than using memory.  Does this argument sound RISC-y?

Note that nothing in the C language requires this particular high-level
language penalty (passing args in memory rather than in registers).
The varargs kludge is for convenience only (yes, I like it, too, and
would chafe at Pascal-like restrictiveness!).
-- 
Eric Black   "Garbage In, Gospel Out"
UUCP:        {sun,pyramid,hplabs,amdcad}!chronon!eric
WELL:        eblack
BIX:         eblack

eric@chronon.UUCP (Eric Black) (05/01/86)

Sorry, but I left out an important point from my previous posting about
vararg difficulties.

My article should in no way be construed as arguing against allowing
a variable number of arguments being passed to a called function.
Rather, it points out that code that *ASSUMES* that varargs are passed
in memory in ascending addresses *IS A HIGHLY MACHINE-DEPENDENT ASSUMPTION*
and is *NOT PORTABLE CODE*.  Library support to handle variable argument
lists in a standardized way is appropriate (see varargs.h on BSD systems
for something which comes very close).  These library routines are quite
simple on a traditional architecture (which is assumed by too many
existing pieces of code -- printf is too many already!).
-- 
Eric Black   "Garbage In, Gospel Out"
UUCP:        {sun,pyramid,hplabs,amdcad}!chronon!eric
WELL:        eblack
BIX:         eblack

ark@alice.UucP (Andrew Koenig) (05/03/86)

I think people are confusing two different meanings for the same term:

	1. the practice of writing programs that accept varying
	numbers of actual parameters by declaring a single formal
	parameter, taking its address, and incrementing that
	address in various devious ways.

	2. the practice of writing programs that accept varying
	numbers of actual parameters and access them using ONLY the
	facilities provided by <varargs.h> .  The particular
	implementation of these facilities may differ from one
	machine to another.

I said I don't know offhand of a machine that can't implement #2.
I am being deluged by descriptions of machines that can't implement #1.

greg@utcsri.UUCP (Gregory Smith) (05/03/86)

In article <236@chronon.chronon.UUCP> eric@chronon.UUCP (Eric Black) writes:
>In article <129@drilex.UUCP> dricej@drilex.UUCP writes:
>>
>>rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to
>>handle varargs. ...
>>... Therefore, a more proper question would be: is there any
>>architecture which is suitable for a C compiler, but not for varargs?
>
>Yes!  I can think of an example close to home... An architecture with
>a large (LARGE) number of registers, a sliding window to allow reference
>to a smaller register set locally within a procedure, and OS support
>for using the register set as a stack (handling overflow/underflow).
>The first <n> arguments are passed in registers via the overlapped
>sliding window, remaining have to be passed in memory.  The problem
>is that no choice of <n> will be correct; you can only make arbitrarily
>small the probability of it not being big enough...  and at the cost of
>additional expense elsewhere...
>I assert that this architecture, and the rest of what goes with this
>particular feature, is particularly well-suited for efficient execution
>of programs written in C.
>
I agree with your assertion. If this machine supports pointers to registers,
you could write a varargs. va_arg() would have to bump a pointer to the last
register arg to a pointer to memory, maybe by calling a 'va_bump' function.
If it doesn't support pointers to register args, then it is in a bit of
trouble with C because this is supposed to be legal:

	f(a) int a;
	{	wombat(&a);
	}
-- 
"For every action there is an equal and opposite malfunction"
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

eric@chronon.UUCP (Eric Black) (05/08/86)

Yes, this is slightly to the side of the original question as
to whether it is POSSIBLE to write a varargs() handler (a la 4.2 manpage)
for any given machine architecture, but the discussion is legitimately
moving around that target...

In article <2694@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes:
>In article <236@chronon.chronon.UUCP> eric@chronon.UUCP (Eric Black) writes:
>>In article <129@drilex.UUCP> dricej@drilex.UUCP writes:
>>>rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to
>>>handle varargs. ...
>>>... Therefore, a more proper question would be: is there any
>>>architecture which is suitable for a C compiler, but not for varargs?

[I guess I answered a slightly different question here:]

>>Yes!  I can think of an example close to home... An architecture with
>>a large (LARGE) number of registers, a sliding window to allow reference
>>    [... description of register stack machine ...]
>>I assert that this architecture, and the rest of what goes with this
>>particular feature, is particularly well-suited for efficient execution
>>of programs written in C.
>>
>I agree with your assertion. If this machine supports pointers to registers,
>you could write a varargs. va_arg() would have to bump a pointer to the last
>register arg to a pointer to memory, maybe by calling a 'va_bump' function.
>If it doesn't support pointers to register args, then it is in a bit of
>trouble with C because this is supposed to be legal:
>
>	f(a) int a;
>	{	wombat(&a);
>	}
>-- 

Yup.  This is legal, and is permitted.  This machine DOES allow you
to take the address of a register, but it's an expensive feature
to support, and we'd like to get rid of it.  Other systems take care
of this at the compiler level, and it crops up with register variables,
not just arguments -- if you take the address of a variable, it can't
reside in a register, but must be copied into memory.  Possible
aliasing with pointer arithmetic gets quite hairy, but that's a
dangerous [and generally non-portable] thing to do in an undisciplined
manner.

This brings me back to my point (sort of).  This is the same problem that
other machines have with register variables and getting at them in
two different ways (by name and at the other end of a pointer).  In
the case of varargs, the "by name" is as a formal parameter, the pointer
is the usual varargs method.  Accessing varargs directly is just as
sloppy as doing something like this:
	foo()
	{
	    int a, b, *intp;

	    intp = &a;
	    *intp = 1;		/* set a to 1 */
	    intp++;
	    *intp = 2;		/* of course, this sets b to 2, doesn't it? */
	}
If you think this is good coding practice, I don't want you working
for me!  If you object to this technique, why is direct accessing of
varargs items OK?

Again, I realize this is not answering the precise question in the
original posting, but it's worth discussing.  Thanks for putting up
with me...

-- 
Eric Black   "Garbage In, Gospel Out"
UUCP:        {sun,pyramid,hplabs,amdcad}!chronon!eric

ark@alice.UucP (Andrew Koenig) (05/10/86)

> Hypothetical but quite beleivable:  On a 68000, pass the first N
> 32-bit integer (int, long, etc.) arguements in data regisers and the
> first M (32-bit) pointer arguments in address registers.  There isn't
> a typeof operator, and the hack of determining the data type by doing
> string manipulations on the quoted type, besides preprocessor
> replacements in quoted strings being a pcc oddity, breaks when faced
> with typedefs.  (I think argument quoting via a different meathod is
> proposed in the current ansi C draft.)
>
> This is true of any architecture with different register types with
> identical size.  (Otherwise the type could be determined by sizeof,
> which I do in the varargs.h implementation I wrote.)  Any proposted
> solutions, other than not having such a compiler on such a machine?

If a pointer argument is passed in a different place from an
integer argument of the same size, then implementing varargs
requires some help from the compiler.

But such an implementation is going to have trouble in any event
because even today there are sometimes programs that forget to,
say, declare the type of an argument.  This is especially true
when that argument is merely passed to some other function.