From: Philip Murray Date: 2006-11-29T06:31:31+09:00 Subject: Ruby DL extension and x86_64 --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--