--Apple-Mail-279--388836258
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	delsp=yes;
	format=flowed

Hi,

I've been trying to use the new GD2 bindings (http:// 
gd2.rubyforge.org), which have worked great... until I deployed on an  
x86_64 server.

Under 64bit, Ruby's DL extension doesn't pass the parameters to the  
shared lib functions correctly as (upto 6, integer/pointer)  
parameters get passed via registers instead of on the stack. Which is  
in contrast to 32bit/x86 where everything gets passed on the stack.

When using gdImageStringFTEx which took 10 parameters, 2 of which are  
doubles. This caused junk to be passed in the parameters from the  
first double parameters onwards to the GD function and subsequently  
segfaulted:

0x0000000800ed8239 in gdImageStringFTEx (im=0x0, brect=0x5e3bc0,  
fg=0, fontlist=0x5c60b0 "./verdana.ttf", ptsize=9, angle=5600, x=0, y=6,
     string=0x7fffffffabe0 "", strex=0x800dc1a56) at gdft.c:937

The parameters _should_ be ptsize=1.0, angle=2.0, x=3, y=4. The  
pointers for string, and strex were also incorrect.

I have attached a patch that allows DL to work correctly on x86_64  
(only) with functions that take floating point parameters, but it has  
a caveat in that you cannot call a function that takes more than 8  
floats/doubles.

The patch isn't portable, so it seems like it would be a good idea to  
convert DL to using Libffi (http://sourceware.org/libffi/) for the  
future (Ruby 2.0?). Using Libffi would make the DL extension much  
simpler and portable across many more platforms.

Thanks to Perry Lorier for being the brains behind the patch!

Cheers

Philip Murray



--Apple-Mail-279--388836258
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name=sym.c.diff
Content-Disposition: attachment;
	filename=sym.c.diff

--- sym.c.orig	Thu Jun 16 11:39:27 2005
+++ sym.c	Wed Nov 29 00:00:14 2006
@@ -361,9 +361,22 @@
 __declspec(noinline)
 # endif
 static int
-rb_dlsym_guardcall(char type, ANY_TYPE *ret, long *stack, void *func)
+rb_dlsym_guardcall(char type, ANY_TYPE *ret,  long *stack, double *sse,
+		void *func)
 {
   char *volatile guard = ALLOCA_N(char, 1); /* guard stack pointer */
+#undef DLSTACK_PROTO
+#define DLSTACK_PROTO   long, long, long, long, long, \
+  			long, long, long, long, long, \
+  			long, long, long, long, long, \
+  			double, double, double, double, \
+  			double, double, double, double
+#undef DLSTACK_ARGS
+#define DLSTACK_ARGS    stack[0], stack[1], stack[2], stack[3], stack[4], \
+  			stack[5], stack[6], stack[7], stack[8], stack[9], \
+  			stack[10], stack[11], stack[12], stack[13], stack[14], \
+  			sse[0], sse[1], sse[2], sse[3], \
+  			sse[4], sse[5], sse[6], sse[7]
   switch(type){
   case '0':
     {
@@ -450,6 +463,9 @@
   int i;
   long ftype;
   void *func;
+  
+  int sses=0;
+  double sse[8];
 
   rb_secure_update(self);
   Data_Get_Struct(self, struct sym_data, sym);
@@ -677,58 +693,58 @@
     switch( sym->type[i+1] ){
     case 'p':
     case 'P':
-      DLSTACK_PUSH_P(ANY2P(args[i]));
-      break;
     case 'a':
     case 'A':
-      DLSTACK_PUSH_P(ANY2P(args[i]));
+    case 'c':
+    case 'h':
+    case 'i':
+    case 'l':
+    case 'f':
+    case 'd':
+	      //printf("arg %i: %x (stack)\n",i,ANY2P(args[i]));
+	      memcpy(sp,&ANY2P(args[i]),sizeof(void*));
+	      sp++;
       break;
+
     case 'C':
-      DLSTACK_PUSH_C(ANY2C(args[i]));
-      break;
-    case 'c':
-      DLSTACK_PUSH_P(ANY2P(args[i]));
+	      //printf("arg %i: '%c' (stack)\n",i,ANY2P(args[i]));
+	      memcpy(sp,&ANY2C(args[i]),sizeof(void*));
+	      sp++;
       break;
     case 'H':
-      DLSTACK_PUSH_H(ANY2H(args[i]));
-      break;
-    case 'h':
-      DLSTACK_PUSH_P(ANY2P(args[i]));
+	      //printf("arg %i: H (stack)\n",i);
+	      memcpy(sp,&ANY2H(args[i]),sizeof(void*));
+	      sp++;
       break;
     case 'I':
-      DLSTACK_PUSH_I(ANY2I(args[i]));
-      break;
-    case 'i':
-      DLSTACK_PUSH_P(ANY2P(args[i]));
+	      //printf("arg %i: %d (stack)\n",i,ANY2I(args[i]));
+	      memcpy(sp,&ANY2I(args[i]),sizeof(void*));
+	      sp++;
       break;
     case 'L':
-      DLSTACK_PUSH_L(ANY2L(args[i]));
-      break;
-    case 'l':
-      DLSTACK_PUSH_P(ANY2P(args[i]));
-      break;
+	      //printf("arg %i: %liL (stack)\n",i,ANY2L(args[i]));
+	      memcpy(sp,&ANY2L(args[i]),sizeof(void*));
+	      sp++;
     case 'F':
-      DLSTACK_PUSH_F(ANY2F(args[i]));
-      break;
-    case 'f':
-      DLSTACK_PUSH_P(ANY2P(args[i]));
+      //printf("arg %i: %fF (sse)\n",i,ANY2F(args[i]));
+      sse[sses++]=*(double*)&ANY2F(args[i]);
       break;
     case 'D':
-      DLSTACK_PUSH_D(ANY2D(args[i]));
-      break;
-    case 'd':
-      DLSTACK_PUSH_P(ANY2P(args[i]));
+      //printf("arg %i: %fLF (sse)\n",i,ANY2D(args[i]));
+      sse[sses++]=ANY2D(args[i]);
       break;
     case 'S':
     case 's':
-      DLSTACK_PUSH_P(ANY2S(args[i]));
+      //printf("arg %i: \"%s\" (stack)\n",i,ANY2S(args[i]));
+      memcpy(sp,&ANY2S(args[i]),sizeof(void*));
+      sp++;
       break;
     }
   }
   DLSTACK_END(sym->type);
 
 #ifdef DLSTACK_GUARD
-  if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, func)) {
+  if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, sse, func)) {
     FREE_ARGS;
     rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
   }
@@ -875,7 +891,7 @@
     if( ANY2S(ret) ){
       val = rb_tainted_str_new2((char*)(ANY2S(ret)));
       DEBUG_CODE({
-	printf("dlfree(%s)\n",(char*)(ANY2S(ret)));
+	//printf("dlfree(%s)\n",(char*)(ANY2S(ret)));
       });
       dlfree((void*)(ANY2S(ret)));
     }

--Apple-Mail-279--388836258--