Ruby DL extension and x86_64

P

Philip Murray

--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));
- break;
case 'a':
case 'A':
- DLSTACK_PUSH_P(ANY2P(args));
+ case 'c':
+ case 'h':
+ case 'i':
+ case 'l':
+ case 'f':
+ case 'd':
+ //printf("arg %i: %x (stack)\n",i,ANY2P(args));
+ memcpy(sp,&ANY2P(args),sizeof(void*));
+ sp++;
break;
+
case 'C':
- DLSTACK_PUSH_C(ANY2C(args));
- break;
- case 'c':
- DLSTACK_PUSH_P(ANY2P(args));
+ //printf("arg %i: '%c' (stack)\n",i,ANY2P(args));
+ memcpy(sp,&ANY2C(args),sizeof(void*));
+ sp++;
break;
case 'H':
- DLSTACK_PUSH_H(ANY2H(args));
- break;
- case 'h':
- DLSTACK_PUSH_P(ANY2P(args));
+ //printf("arg %i: H (stack)\n",i);
+ memcpy(sp,&ANY2H(args),sizeof(void*));
+ sp++;
break;
case 'I':
- DLSTACK_PUSH_I(ANY2I(args));
- break;
- case 'i':
- DLSTACK_PUSH_P(ANY2P(args));
+ //printf("arg %i: %d (stack)\n",i,ANY2I(args));
+ memcpy(sp,&ANY2I(args),sizeof(void*));
+ sp++;
break;
case 'L':
- DLSTACK_PUSH_L(ANY2L(args));
- break;
- case 'l':
- DLSTACK_PUSH_P(ANY2P(args));
- break;
+ //printf("arg %i: %liL (stack)\n",i,ANY2L(args));
+ memcpy(sp,&ANY2L(args),sizeof(void*));
+ sp++;
case 'F':
- DLSTACK_PUSH_F(ANY2F(args));
- break;
- case 'f':
- DLSTACK_PUSH_P(ANY2P(args));
+ //printf("arg %i: %fF (sse)\n",i,ANY2F(args));
+ sse[sses++]=*(double*)&ANY2F(args);
break;
case 'D':
- DLSTACK_PUSH_D(ANY2D(args));
- break;
- case 'd':
- DLSTACK_PUSH_P(ANY2P(args));
+ //printf("arg %i: %fLF (sse)\n",i,ANY2D(args));
+ sse[sses++]=ANY2D(args);
break;
case 'S':
case 's':
- DLSTACK_PUSH_P(ANY2S(args));
+ //printf("arg %i: \"%s\" (stack)\n",i,ANY2S(args));
+ memcpy(sp,&ANY2S(args),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--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,588
Members
45,093
Latest member
Vinaykumarnevatia00

Latest Threads

Top