From: anhaeupl@late.e-technik.uni-erlangen.DE (Bernd Anhaeupl)
Subject: gcc 2.2.2 stdarg/varargs bug on hp9k7xx-hpux (with patch)
Organization: GNUs Not Usenet
Distribution: gnu
Date: Mon, 7 Sep 1992 13:19:46 GMT

hpux-Version: 	8.07
gcc-Version:  	2.2.2
config:       	hp720-hpux
	      	(with gas 1.36 from utah)
Problem: 	<stdarg.h> and <varargs.h> do not work
Example:
------------------------------------ cut here ----------------------------------
#ifdef STDARG
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <stdarg.h>

void t1(int n,...)
{
    va_list args;

    double fa1,fa2,fa3;
    int    a1,a2,a3;

    fa1=fa2=fa3=a1=a2=a3=0;
    va_start(args,n);
    fa1=va_arg(args,double);
    a1 =va_arg(args,int);
    fa2=va_arg(args,double);

    printf("varargs: (%d,%d,%d)[%g,%g,%g]\n",a1,a2,a3,fa1,fa2,fa3);
    va_end(args);
}

int main()
{
    t1(0,1.0,1,2.0);
    printf("Hello, world!\ncos(0)=%f\n",cos(0));
    return EXIT_SUCCESS;
}
#else
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <varargs.h>


void t1(va_alist)
va_dcl
{
    va_list args;

    double fa1,fa2,fa3;
    int    a1,a2,a3;

    fa1=fa2=fa3=a1=a2=a3=0;
    va_start(args);
    a1 =va_arg(args,int);
    fa1=va_arg(args,double);
    fa2=va_arg(args,double);
    a2 =va_arg(args,int);
    fa3=va_arg(args,double);

    printf("varargs: (%d,%d,%d)[%g,%g,%g]\n",a1,a2,a3,fa1,fa2,fa3);

    va_end(args);
}

int main()
{
    t1(1,1.0,2.0,2,3.0);
    printf("Hello, world!\ncos(0)=%f\n",cos(0));
    return EXIT_SUCCESS;
}
#endif
-------------------------------- cut here -----------------------------

Program output after compilation with gcc -g -DSTDARG test.c -lM:
without patch below (wrong)		with patch below (correct)
-----------------------------------	-----------------------------------
varargs: (1,0,0)[7.39631e+97,2,0]	varargs: (1,0,0)[1,2,0]
Hello, world!				Hello, world!				
cos(0)=1.000000				cos(0)=1.000000				
-----------------------------------	-----------------------------------	
program output after compilation with gcc -g test.c -lM:
without patch below (wrong)		with patch below (correct)
------------------------------------	------------------------------------	
varargs: (1,2,0)[7.39631e+97,2,3]	[varargs: (1,2,0)[1,2,3]
Hello, world!				Hello, world!				
cos(0)=1.000000				cos(0)=1.000000				
------------------------------------	------------------------------------	

You see that gnus vararg stuff does not find floating point arguments passed
in registers.

Temporary Solution:	
Replace va-hp800.h with
-----------------------------cut here ----------------------------------
/*  
   Patch for GNUs varargs/stdarg implementation on HP-UX 8.07
   Bernd Anhdupl, LATE, Uni Erlangen, Germany    08/06/92
   (anhaeupl@late.e-technik.uni-erlangen.de)

   The following code seems to work. Note, that the HP-UX linker (ld)
   can ensure (by generating extra code), that floating point arguments, 
   which are passed through floating point registers are copied to the 
   corresponding general registers. Therefore you must only generate the
   proper code to store the general registers arg0...arg3 at the
   corresponding stack positions.
*/
#if __GNUC__ > 1
typedef void* va_list;
#  define __va_rounded_size(TYPE)  \
    (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
#  ifdef _STDARG_H
typedef struct
{
  char *__va_stack_start;	/* Real start of stack args. */
  char *__va_int;		/* Pointer to the general register */
				/* args and stack. */
  char *__va_float;		/* Pointer to the fp register args.  */
  char *__va_double;
} __gnu_va_list;
/*
   __builtin_saveregs should be rewritten, since it is not necessary to
   store the floating point registers, if the functions .EXTERN statemant
   is correct. (You have to tell the linker that the function expects the
   arguments in general registers.)
*/
#define va_start(AP,LASTARG) ((AP) = ((__gnu_va_list *)__builtin_saveregs())->__va_int)
#  else
extern void * __va_save();
/*
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! Implementation (must be moved to libgcc.a): !!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
void *__va_save(int*arg0,int*arg1,int*arg2,int*arg3)
{
    return arg0+1;
}
*/
#define va_alist  __arg0,__arg1,__arg2,__arg3
#define va_dcl
/* since registers have no address, the following call ensures that 
   (general) register arguments are stored on the stack */
#define va_start(AP) ((AP) = __va_save(&__arg0,&__arg1,&__arg2,&__arg3))
#  endif /* _STDARG_H */

#define va_arg(AP, TYPE) 			\
  ( ( (__va_rounded_size(TYPE) <= 8)		\
     ? ( (AP)-= __va_rounded_size (TYPE),	\
	(__alignof__ (TYPE) > 4 		\
	 ? ((int)(AP) &= ~(0x7))		\
	 : 0))					\
     : (int)((AP) -= sizeof (TYPE *))),		\
   ( (__va_rounded_size(TYPE) <= 8) 		\
    ? *(TYPE *)(AP)				\
    : **(TYPE **)(AP)))

#define va_end(AP)

#else /* __GNUCC__ > 1 */
#error wrong gcc version
#endif /* __GNUCC__ > 1 */
------------------------------------ cut here ----------------------------------
and add the necessary function __va_save(int&,int&,int&,int&) (see comment above)
to libgcc.a

This patch also makes GNU's varargs/stdarg stuff compatible with HP's.

Bernd Anhdupl
(anhaeupl@late.e-technik.uni-erlangen.de)



ps: Does anybody have a patch for the ARGW4 bug? 
    Please respond via email!

(for example: the followin program
---------------------- cut here ------------------------
#include <stdio.h>
#include <stdlib.h>

void test(double x1,int x2, double x3)
{
    printf("%g,%d,%g",x1,x2,x3);
}

int main(void)
{
    test(1,2,3);
    return EXIT_SUCCESS;
}
--------------------- cut here ------------------------
results in
-------------------------------------------------------
gcc -g test.c
/usr/tmp/cca21836.s:55:Illegal argument description: 4
-------------------------------------------------------
). Please respond via e-mail.



Newsgroups: gnu.gcc.bug