Subject: bugfix: incorrect va_arg() definition for 32bit MIPS

From: Hiroyuki Machida <[email-masked]>
Date: Wed, 26 Jan 2000 13:27:53 +0900

Hi.
I have been building gcc 2.95.2 on 32bit MIPS/Linux box.
During this work, I found a inverted 'ifdef' on defining 
va_arg() macro in gcc/ginclude/va-mips.h.
That is, definition of va_arg for 32bit little endian and 32bit big
endian is inverted.

You can repeat this problem running a attached test program.
I guess gcc on IRIX 5.? or O32 ABI box has same problem.
Have you ever experienced same problem on 32bit MIPS box?

Sample fix is attached at the bottom.

VERSION:
	gcc 2.95.2 on MIPS/Linux
	gcc 2.7.2  on MIPS/Linux 
	egcs-1.0.2 on MIPS/Linux

REPEAT BY:

Compile and run this program. 
The program will print "OK", if va_arg() accept args correclty.

/*
 * 
 * stdarg.c  -- Simple stdarg test.
 *	Pass #of pairs and (type, value) pairs using stdarg.h.
 *	And check if passed values are correctly accepted.
 *
 */

#include<stdarg.h>

int foo(int nargs, ...)
{
	va_list ap;
	int i;
	int ng = 0;
	long long expected;
	long long passed;

	/* get # of args */
	va_start(ap, nargs);
	printf("  # of args:%d\n",nargs);

	for (i=1; i<= nargs ; i++) {
		char type;
		int d; long long ll; char c; char *s;

		/* calc. expceted value */
		expected=i; 
		if ( expected & 1 ) expected = -expected;

		/* get type of the arg */
		type = (char ) va_arg(ap, char);
		switch (type) {
		   case 'i': /* int */
			d = va_arg(ap, int);
			passed=d; 
			printf("%10s: expected:%3lld,\t passed:%3lld\n",
				"int", expected, passed);
			if ( passed != expected) ng ++;
			break;
		  case 'L':  /* long long */
			ll = va_arg(ap, long long);
			passed=ll;
			printf("%10s: expected:%3lld,\t passed:%3lld\n",
				"long long", expected, passed);
			if ( passed != expected) ng ++;
			break;
		  case 'c':  /* char */
			c = (char) va_arg(ap, char);
			passed=(long long) (c - '0');
			printf("%10s: expected:%3lld,\t passed:%3lld\n",
				"char", expected, passed);
			if ( passed != expected) ng ++;
			break;
		  case 's':  /* char * */
			s = va_arg(ap, char *);
			passed=(long long)atol(s);
			printf("%10s: expected:%3lld,\t passed:%3lld\n",
				"string", expected, passed);
			if ( passed != expected) ng ++;
			break;
		  default:  /* Unknown */
			printf("  unkown type:%4d: argptr:0x%8.8x\n",
				type,(void *)ap);
			ng ++;
			break;
		}
	}
	va_end(ap);
	return ng;
}

int main()
{
	int ng;

	printf("*\n");
	printf("* Simple stdarg test.\n");
	printf("*\n");

	/* Pass # of pairs and  (type, order<*>) pairs  */
	/* order<*> number must be minus value if order is odd */
	ng = foo(6,
		'i', -1,
		'c', '2',
		'L', (long long)-3,
		's', "4",
		'i', -5 ,
		'c', '6');

	if (ng) {
		printf("NG\n");
	}
	else {
		printf("OK\n");
	}
	return ng;
}

SAMPLE FIX:

gcc/ginclude/va-mips.h

retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
--- va-mips.h	1999/05/19 13:14:31	1.1.1.1
+++ va-mips.h	1999/11/08 09:48:26	1.2
@@ -254,19 +254,19 @@ void va_end (__gnuc_va_list);		/* Define
 
 #ifdef __MIPSEB__
 /* For big-endian machines.  */
+#define va_arg(__AP, __type)						    \
+  ((__type *) (void *) (__AP = (char *) ((__alignof__(__type) > 4	    \
+				? ((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8	    \
+				: ((__PTRDIFF_TYPE__)__AP + 4 - 1) & -4)    \
+					 + __va_rounded_size(__type))))[-1]
+#else
+/* For little-endian machines.  */
 #define va_arg(__AP, __type)					\
   ((__AP = (char *) ((__alignof__ (__type) > 4			\
 		      ? ((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8	\
 		      : ((__PTRDIFF_TYPE__)__AP + 4 - 1) & -4)	\
 		     + __va_rounded_size (__type))),		\
    *(__type *) (void *) (__AP - __va_rounded_size (__type)))
-#else
-/* For little-endian machines.  */
-#define va_arg(__AP, __type)						    \
-  ((__type *) (void *) (__AP = (char *) ((__alignof__(__type) > 4	    \
-				? ((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8	    \
-				: ((__PTRDIFF_TYPE__)__AP + 4 - 1) & -4)    \
-					 + __va_rounded_size(__type))))[-1]
 #endif
 #endif
 #endif /* ! defined (__mips_eabi)  */

---
Hiroyuki Machida		[email-masked]
Creative Station		SCEI / Sony Corp.