Patch: Porting EMBOSS to LinuxPPC ...

Michael Schmitz schmitz at mail.biophys.uni-duesseldorf.de
Mon Sep 18 18:21:54 UTC 2000


Hi list,

the attached diff is what I came up with in order to get EMBOSS ported to
the PowerPC architecture. It's not pretty, but I've not found a nice
portable way of dealing with the problem, so I would appreciate suggestions 
on how else to address this problem. The current solution at least allows
for running EMBOSS on PowerPC systems. 

Background information (as in: what exactly is the problem?, lengthy):

Symptom of the problem is each EMBOSS application segfaulting early in
embInit. The cause of this is variable argument list functions messing up
their va_lists resulting in access to bogus memory addresses. It all
happens because gcc on the PowerPC architecture uses a weird calling
convention for variable argument lists, unlike most other architectures.

va_list is declared from __gnuc_va_list:

typedef __gnuc_va_list va_list;

common for pretty much all architectures.

The typical declaration for __gnuc_va_list would be:

#if defined(__svr4__) || defined(_AIX) || defined(_M_UNIX) || defined(__NetBSD__)
typedef char *__gnuc_va_list;
#else
typedef void *__gnuc_va_list;

- essentially just a pointer. 

LinuxPPC uses the SysV.4 convention which declares

typedef struct __va_list_tag {
  char gpr;                     /* index into the array of 8 GPRs stored in the
                                   register save area gpr=0 corresponds to r3,
                                   gpr=1 to r4, etc. */
  char fpr;                     /* index into the array of 8 FPRs stored in the
                                   register save area fpr=0 corresponds to f1,
                                   fpr=1 to f2, etc. */
  char *overflow_arg_area;      /* location on stack that holds the next
                                   overflow argument */
  char *reg_save_area;          /* where r3:r10 and f1:f8, if saved are stored */
} __va_list[1], __gnuc_va_list[1];

- not a simple pointer, apparently. 

See the gcc include's stdarg.h and va-ppc.h headers for more details. 

The practical upshot of this is twofold: 

- pointers to va_list arguments must be passed on Intel and others if the
va_list is expected to change by the called function. ajFmtVfmt() makes
use of this to call the appropriate format conversion functions while
parsing the format string. 
On PowerPC, pointers to va_list arguments must not be passed but the
va_list itself must be passed (I don't quite see why but I've tried). 

- When passing va_list arguments around on PowerPC, keep in mind that the
va_list will always change, regardless of passing it as a pointer or not.
This is particularly nasty in ajFmtStr(), ajFmtPrintS(), ajFmtPrintAppS()
where ajFmtVfmt() and friends are called within the error handler context,
exhausting the argument list rapidly. The original va_list contents should
be saved and restored in case the error handler trapped some recoverable
error. 

Enough of the gory details, and please don't blame me for the broken
PowerPC calling conventions. Please CC: me on replies as I'm not
subscribed to the list.

	Michael Schmitz
-------------- next part --------------
--- ajax/ajfmt.c.org	Mon Sep 18 09:26:37 2000
+++ ajax/ajfmt.c	Mon Sep 18 16:49:54 2000
@@ -69,7 +69,7 @@
 ** As for C RTL but prints null if given a null pointer.
 **
 ** @param [r] code [int] Format code specified (usually s)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -79,11 +79,11 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_s(int code, va_list* app,
+static void cvt_s(int code, VALIST ap,
 		  int put(int c, void* cl), void* cl,
 		  unsigned int* flags, int width, int precision) {
 
-  char *str = va_arg(*app, char *);
+  char *str = va_arg(VA_V(ap), char *);
 
   if (str)
     ajFmtPuts(str, strlen(str), put, cl, flags,
@@ -100,7 +100,7 @@
 ** Conversion for %d to print integer
 **
 ** @param [r] code [int] Format code specified (usually d)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list*] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -110,7 +110,7 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_d(int code, va_list* app,
+static void cvt_d(int code, VALIST ap,
 		  int put(int c, void* cl), void* cl,
 		  unsigned int* flags, int width, int precision) {
 
@@ -120,13 +120,13 @@
   char *p = buf + sizeof buf;
 
   if (flags['l']) {
-    val = (long) va_arg(*app, long);
+    val = (long) va_arg(VA_V(ap), long);
   }
   else if (flags['h']) {
-    val = (long) va_arg(*app, int); /* ANSI C converts short to int */
+    val = (long) va_arg(VA_V(ap), int); /* ANSI C converts short to int */
   }
   else {
-    val = (long) va_arg(*app, int);
+    val = (long) va_arg(VA_V(ap), int);
   }
 
   if (val == INT_MIN)
@@ -154,7 +154,7 @@
 ** Conversion for %u to print unsigned integer
 **
 ** @param [r] code [int] Format code specified (usually u)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] app [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -164,7 +164,7 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_u(int code, va_list* app,
+static void cvt_u(int code, VALIST ap,
 		  int put(int c, void* cl), void* cl,
 		  unsigned int* flags, int width, int precision) {
 
@@ -174,11 +174,11 @@
   char *p = buf + sizeof buf;
 
   if (flags['l'])
-    m  = va_arg(*app, unsigned long);
+    m  = va_arg(VA_V(ap), unsigned long);
   else if (flags['h'])
-    m  = va_arg(*app, unsigned int); /* ANSI C converts short to int */
+    m  = va_arg(VA_V(ap), unsigned int); /* ANSI C converts short to int */
   else
-    m  = va_arg(*app, unsigned int);
+    m  = va_arg(VA_V(ap), unsigned int);
 
   do
     *--p = ajSysItoC(m%10 + '0');
@@ -195,7 +195,7 @@
 ** Conversion for %o to print unsigned integer as octal
 **
 ** @param [r] code [int] Format code specified (usually o)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -205,7 +205,7 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_o(int code, va_list* app,
+static void cvt_o(int code, VALIST ap,
 		  int put(int c, void* cl), void* cl,
 		  unsigned int* flags, int width, int precision) {
 
@@ -214,11 +214,11 @@
   char *p = buf + sizeof buf;
 
   if (flags['l'])
-    m = va_arg(*app, unsigned long);
+    m = va_arg(VA_V(ap), unsigned long);
   if (flags['h'])
-    m = va_arg(*app, unsigned int); /* ANSI C converts short to int */
+    m = va_arg(VA_V(ap), unsigned int); /* ANSI C converts short to int */
   else
-    m = va_arg(*app, unsigned int);
+    m = va_arg(VA_V(ap), unsigned int);
 
   do
     *--p = ajSysItoC((m&0x7) + '0');
@@ -238,7 +238,7 @@
 ** Conversion for %x to print unsigned integer as hexadecimal
 **
 ** @param [r] code [int] Format code specified (usually x)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -248,7 +248,7 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_x(int code, va_list* app,
+static void cvt_x(int code, VALIST ap,
 		  int put(int c, void* cl), void* cl,
 		  unsigned int* flags, int width, int precision) {
 
@@ -257,11 +257,11 @@
   char *p = buf + sizeof buf;
 
   if (flags['l'])
-    m = va_arg(*app, unsigned long);
+    m = va_arg(VA_V(ap), unsigned long);
   else if (flags['h'])
-    m = va_arg(*app, unsigned int); /* ANSI C converts short to int */
+    m = va_arg(VA_V(ap), unsigned int); /* ANSI C converts short to int */
   else
-    m = va_arg(*app, unsigned int);
+    m = va_arg(VA_V(ap), unsigned int);
 
   if (code == 'X') {
     do
@@ -293,7 +293,7 @@
 ** Conversion for %p to print pointers of type void* as hexadecimal
 **
 ** @param [r] code [int] Format code specified (usually p)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -303,10 +303,10 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_p(int code, va_list* app,
+static void cvt_p(int code, VALIST ap,
 	int put(int c, void* cl), void* cl,
 	unsigned int* flags, int width, int precision) {
-	unsigned long m = (unsigned long)va_arg(*app, void*);
+	unsigned long m = (unsigned long)va_arg(VA_V(ap), void*);
 	char buf[43];
 	char *p = buf + sizeof buf;
 	precision = INT_MIN;
@@ -326,7 +326,7 @@
 ** by default, so char is always promoted to int by the time it reaches here.
 **
 ** @param [r] code [int] Format code specified (usually c)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -336,7 +336,7 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_c(int code, va_list* app,
+static void cvt_c(int code, VALIST ap,
 	int put(int c, void* cl), void* cl,
 	unsigned int* flags, int width, int precision) {
 	if (width == INT_MIN)
@@ -347,7 +347,7 @@
 	}
 	if (!flags['-'])
 		pad(width - 1, ' ');
-	(void) put(ajSysItoUC(va_arg(*app, int)), cl);
+	(void) put(ajSysItoUC(va_arg(VA_V(ap), int)), cl);
 	if ( flags['-'])
 		pad(width - 1, ' ');
 }
@@ -364,7 +364,7 @@
 ** of the format for sprintf.
 **
 ** @param [r] code [int] Format code specified (usually f)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -374,7 +374,7 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_f(int code, va_list* app,
+static void cvt_f(int code, VALIST ap,
 		  int put(int c, void* cl), void* cl,
 		  unsigned int* flags, int width, int precision) {
   char buf[DBL_MAX_10_EXP+1+1+99+1];
@@ -397,7 +397,7 @@
     fmt[i++] = ajSysItoC(code);
     fmt[i] = '\0';
 
-    (void) sprintf(buf, fmt, va_arg(*app, double));
+    (void) sprintf(buf, fmt, va_arg(VA_V(ap), double));
   }
 
 				/* now write string and support width */
@@ -412,7 +412,7 @@
 ** Conversion for %S to print a string
 **
 ** @param [r] code [int] Format code specified (usually S)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -422,10 +422,10 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_S(int code, va_list* app,
+static void cvt_S(int code, VALIST ap,
 	int put(int c, void* cl), void* cl,
 	unsigned int* flags, int width, int precision) {
-	AjPStr str1 = va_arg(*app, AjPStr);
+	AjPStr str1 = va_arg(VA_V(ap), AjPStr);
 	if (str1) {
 	  ajFmtPuts(str1->Ptr, str1->Len, put, cl, flags,
 		    width, precision);
@@ -441,7 +441,7 @@
 ** Conversion for %b to print a boolean as a 1 letter code (Y or N)
 **
 ** @param [r] code [int] Format code specified (usually b)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -451,10 +451,10 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_b(int code, va_list* app,
+static void cvt_b(int code, VALIST ap,
 	int put(int c, void* cl), void* cl,
 	unsigned int* flags, int width, int precision) {
-	AjBool bl = va_arg(*app, AjBool);
+	AjBool bl = va_arg(VA_V(ap), AjBool);
 	if (bl)
 	  ajFmtPuts("Y", 1, put, cl, flags,
 		width, precision);
@@ -469,7 +469,7 @@
 ** Conversion for %B to print a boolean as text (Yes or No)
 **
 ** @param [r] code [int] Format code specified (usually B)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -479,10 +479,10 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_B(int code, va_list* app,
+static void cvt_B(int code, VALIST ap,
 	int put(int c, void* cl), void* cl,
 	unsigned int* flags, int width, int precision) {
-	AjBool bl = va_arg(*app, AjBool);
+	AjBool bl = va_arg(VA_V(ap), AjBool);
 	if (bl)
 	  ajFmtPuts("Yes", 3, put, cl, flags,
 		width, precision);
@@ -497,7 +497,7 @@
 ** Conversion for %D to print a datetime value
 **
 ** @param [r] code [int] Format code specified (usually D)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -507,10 +507,10 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_D(int code, va_list* app,
+static void cvt_D(int code, VALIST ap,
 	int put(int c, void* cl), void* cl,
 	unsigned int* flags, int width, int precision) {
-        AJTIME *time =  va_arg(*app, AJTIME *);
+        AJTIME *time =  va_arg(VA_V(ap), AJTIME *);
 	struct tm *mytime = time->time;
 
 	char buf[280];
@@ -537,7 +537,7 @@
 ** Conversion for %F to print a file object
 **
 ** @param [r] code [int] Format code specified (usually F)
-** @param [r] app [va_list*] Original arguments at current position
+** @param [r] ap [va_list] Original arguments at current position
 ** @param [r] put [int function] Standard function
 ** @param [r] cl [void*] Standard
 ** @param [r] flags [unsigned int*] Flags (after the %)
@@ -547,10 +547,10 @@
 ** @@
 ******************************************************************************/
 
-static void cvt_F(int code, va_list* app,
+static void cvt_F(int code, VALIST ap,
 	int put(int c, void* cl), void* cl,
 	unsigned int* flags, int width, int precision) {
-	AjPFile fil = va_arg(*app, AjPFile);
+	AjPFile fil = va_arg(VA_V(ap), AjPFile);
 	if (fil && fil->Name) {
 	  ajFmtPuts(fil->Name->Ptr, fil->Name->Len, put, cl, flags,
 		    width, precision);
@@ -895,7 +895,7 @@
 ******************************************************************************/
 
 AjPStr ajFmtStr (const char* fmt, ...) {
-	va_list ap;
+	va_list ap, save_ap;
 	volatile AjBool okay=ajFalse;
 	int len =20;
 	AjPStr fnew;
@@ -903,6 +903,8 @@
 	fnew = ajStrNewL (len);
 	va_start(ap, fmt);
 
+	__va_copy(save_ap, ap);
+
 	while(!okay){
 	  AJTRY
 	    len = ajFmtVfmtCL(fnew->Ptr, fnew->Res, fmt, ap);
@@ -911,6 +913,7 @@
        	  ELSE
 	    len = fnew->Res *2;       /* double the memory and try again */
 	    (void) ajStrModL(&fnew, len);
+	    __va_copy(ap, save_ap);
 	  END_TRY;
 	}  
 	va_end(ap);
@@ -939,7 +942,7 @@
 
 AjPStr ajFmtPrintS (AjPStr* pthis, const char* fmt, ...) {
         volatile AjPStr thys;
-	va_list ap;
+	va_list ap, save_ap;
 	volatile AjBool okay = ajFalse;
 	int len ;
 
@@ -949,6 +952,8 @@
 	thys = *pthis;
 	len = thys->Res;
 
+	__va_copy(save_ap, ap);
+
 	while(!okay){
 	  AJTRY
 	    len = ajFmtVfmtCL(thys->Ptr, thys->Res, fmt, ap);
@@ -960,6 +965,7 @@
 	      /* create new one with twice the memory */
 	      (void) ajStrModL(pthis, len);
 	      thys = *pthis;
+	      __va_copy(ap, save_ap);
 	    }
 	    else{
 	      thys= 0;
@@ -995,7 +1001,7 @@
 
 AjPStr ajFmtPrintAppS(AjPStr* pthis, const char* fmt, ...) {
         volatile AjPStr thys;
-	va_list ap;
+	va_list ap, save_ap;
 	volatile AjBool okay = ajFalse;
 	int len ;
 
@@ -1005,6 +1011,8 @@
 	thys = *pthis;
 	len = thys->Res;
 
+	__va_copy(save_ap, ap);
+
 	while(!okay){
 	  AJTRY
 	    len = ajFmtVfmtCL(&thys->Ptr[thys->Len], thys->Res-thys->Len,
@@ -1017,6 +1025,7 @@
 	      /* create new one with twice the memory */
 	      (void) ajStrModL(pthis, len);
 	      thys = *pthis;
+	      __va_copy(ap, save_ap);
 	    }
 	    else{
 	      thys= 0;
@@ -1175,7 +1184,7 @@
       }
       c = *fmt++;		/* finally, next character is the code */
       (void) assert(cvt[(int)c]);		/* we need a defined routine */
-      (*cvt[(int)c])(c, &ap, put, cl, (unsigned int *)flags, width, precision);
+      (*cvt[(int)c])(c, VA_P(ap), put, cl, (unsigned int *)flags, width, precision);
     }
   }
 }
--- ajax/ajfmt.h.org	Mon Jul 10 16:26:21 2000
+++ ajax/ajfmt.h	Mon Sep 18 16:59:19 2000
@@ -9,7 +9,18 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include "ajexcept.h"
-typedef void (*Fmt_T)(int code, va_list *app,
+
+#if defined(__PPC__) && defined(_CALL_SYSV)
+#define VALIST va_list
+#define VA_P(x) (x)
+#define VA_V(x) (x)
+#else
+#define VALIST va_list*
+#define VA_P(x) (&x)
+#define VA_V(x) (*x)
+#endif
+
+typedef void (*Fmt_T)(int code, VALIST ap,
 	int put(int c, void *cl), void *cl,
 	unsigned int flags[256], int width, int precision);
 


More information about the EMBOSS mailing list