diff options
-rw-r--r-- | ext/dl/dl.h | 23 | ||||
-rw-r--r-- | ext/dl/extconf.rb | 13 | ||||
-rw-r--r-- | ext/dl/sym.c | 124 |
3 files changed, 122 insertions, 38 deletions
diff --git a/ext/dl/dl.h b/ext/dl/dl.h index a88e95d66f..ceee8c5384 100644 --- a/ext/dl/dl.h +++ b/ext/dl/dl.h @@ -142,8 +142,8 @@ #if defined(USE_INLINE_ASM) # if defined(__i386__) && defined(__GNUC__) -# define ASM_START(type) -# define ASM_END(type) +# define ASM_START(sym) +# define ASM_END(sym) # define ASM_PUSH_C(x) asm volatile ("pushl %0" :: "g" (x)); # define ASM_PUSH_H(x) asm volatile ("pushl %0" :: "g" (x)); # define ASM_PUSH_I(x) asm volatile ("pushl %0" :: "g" (x)); @@ -158,15 +158,16 @@ # else # error --with-asm is not supported on this machine # endif -#else -# define ASM_START(type) -# define ASM_END(type) -# define ASM_PUSH_C(x) -# define ASM_PUSH_I(x) -# define ASM_PUSH_L(x) -# define ASM_PUSH_P(x) -# define ASM_PUSH_F(x) -# define ASM_PUSH_D(x) +#elif defined(USE_DLSTACK) +# define ASM_START(sym) +# define ASM_END(sym) +# define ASM_PUSH_C(x) memcpy(sp,&x,1); sp++; +# define ASM_PUSH_H(x) memcpy(sp,&x,sizeof(short)); sp++; +# define ASM_PUSH_I(x) memcpy(sp,&x,sizeof(int)); sp++; +# define ASM_PUSH_L(x) memcpy(sp,&x,sizeof(long)); sp++; +# define ASM_PUSH_P(x) memcpy(sp,&x,sizeof(void*)); sp++; +# define ASM_PUSH_F(x) memcpy(sp,&x,sizeof(float)); sp+=sizeof(float)/sizeof(long); +# define ASM_PUSH_D(x) memcpy(sp,&x,sizeof(double)); sp+=sizeof(double)/sizeof(long); #endif extern VALUE rb_mDL; diff --git a/ext/dl/extconf.rb b/ext/dl/extconf.rb index d119ed1d6d..6dc6abca4e 100644 --- a/ext/dl/extconf.rb +++ b/ext/dl/extconf.rb @@ -13,6 +13,7 @@ if( ARGV.include?("--help") ) --with-type-float strictly use type 'float' --with-asm use the embedded assembler for passing arguments. (this option is available for i386 machine now.) + --with-dlstack use a stack emulation for constructing function call. [experimental] --with-args=<max_arg>,<max_cbarg>,<max_cbent> <max_arg>: maximum number of arguments of the function <max_cbarg>: maximum number of arguments of the callback @@ -32,6 +33,7 @@ if (Config::CONFIG['CC'] =~ /gcc/) && (Config::CONFIG['arch'] =~ /i.86/) else $with_asm = false end +$with_dlstack = false $with_type_int = try_run(<<EOF) int main(){ return sizeof(int) == sizeof(long); } @@ -63,10 +65,11 @@ $with_type_short = enable_config("type-short", $with_type_short) $with_type_float = enable_config("type-float", $with_type_float) $with_asm = enable_config("asm", $with_asm) +$with_dlstack = enable_config("dlstack", $with_dlstack) args = with_config("args") max_arg = max_cbarg = max_cbent = nil -if( $with_asm ) +if( $with_asm || $with_dlstack ) $with_type_char = true $with_type_short = true $with_type_float = true @@ -106,8 +109,12 @@ def dlc_define(const) "#endif\n" end -if( $with_asm ) - $dlconfig_h << "#define USE_INLINE_ASM\n" +if( $with_dlstack ) + $dlconfig_h << "#define USE_DLSTACK\n" +else + if( $with_asm ) + $dlconfig_h << "#define USE_INLINE_ASM\n" + end end if( $with_type_char ) $dlconfig_h << "#define WITH_TYPE_CHAR\n" diff --git a/ext/dl/sym.c b/ext/dl/sym.c index 7f9793fa51..996831bec2 100644 --- a/ext/dl/sym.c +++ b/ext/dl/sym.c @@ -101,7 +101,7 @@ rb_dlsym_new(void (*func)(), const char *name, const char *type) data->name = name ? strdup(name) : NULL; data->type = type ? strdup(type) : NULL; data->len = type ? strlen(type) : 0; -#ifndef USE_INLINE_ASM +#if !(defined(USE_INLINE_ASM) || defined(USE_DLSTACK)) if( data->len - 1 > MAX_ARG ){ rb_raise(rb_eDLError, "maximum number of arguments is %d.", MAX_ARG); }; @@ -268,6 +268,47 @@ rb_dlsym_inspect(VALUE self) return val; } +static int +stack_size(struct sym_data *sym) +{ + int i; + int size; + + size = 0; + for( i=1; i < sym->len; i++ ){ + switch(sym->type[i]){ + case 'C': + case 'H': + case 'I': + case 'L': + size += sizeof(long); + break; + case 'F': + size += sizeof(float); + break; + case 'D': + size += sizeof(double); + break; + case 'c': + case 'h': + case 'i': + case 'l': + case 'f': + case 'd': + case 'p': + case 'P': + case 's': + case 'S': + case 'a': + case 'A': + size += sizeof(void*); + break; + default: + return -(sym->type[i]); + } + } + return size; +} VALUE rb_dlsym_call(int argc, VALUE argv[], VALUE self) @@ -478,9 +519,43 @@ rb_dlsym_call(int argc, VALUE argv[], VALUE self) func = sym->func; -#ifdef USE_INLINE_ASM - ASM_START(sym->type); - for( i = sym->len - 2; i >= 0; i-- ){ +#if defined(USE_INLINE_ASM) || defined(USE_DLSTACK) + { +#if defined(USE_DLSTACK) +#define DLSTACK_PROTO long,long,long,long,long,\ + long,long,long,long,long,\ + long,long,long,long,long +#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] + int stk_size; + long *stack, *sp; + + stk_size = stack_size(sym); + if( stk_size < 0 ){ + FREE_ARGS; + rb_raise(rb_eDLTypeError, "unknown type '%c'.", -stk_size); + } + else if( stk_size > (int)(sizeof(long) * 15) ){ + FREE_ARGS; + rb_raise(rb_eArgError, "too many arguments."); + stk_size = sizeof(long) * 15; + } + stack = (long*)alloca(stk_size); + sp = stack; +#elif defined(USE_INLINE_ASM) +#define DLSTACK_PROTO +#define DLSTACK_ARGS +#endif + + ASM_START(sym); + +#if defined(USE_DLSTACK) + for( i = 0; i <= sym->len -2; i++ ) +#else + for( i = sym->len - 2; i >= 0; i-- ) +#endif + { switch( sym->type[i+1] ){ case 'p': case 'P': @@ -538,71 +613,72 @@ rb_dlsym_call(int argc, VALUE argv[], VALUE self) switch( sym->type[0] ){ case '0': { - void (*f)() = func; - f(); + void (*f)(DLSTACK_PROTO) = func; + f(DLSTACK_ARGS); }; break; case 'P': case 'p': { - void * (*f)() = func; - ret.p = f(); + void * (*f)(DLSTACK_PROTO) = func; + ret.p = f(DLSTACK_ARGS); }; break; case 'C': case 'c': { - char (*f)() = func; - ret.c = f(); + char (*f)(DLSTACK_PROTO) = func; + ret.c = f(DLSTACK_ARGS); }; break; case 'H': case 'h': { - short (*f)() = func; - ret.h = f(); + short (*f)(DLSTACK_PROTO) = func; + ret.h = f(DLSTACK_ARGS); }; break; case 'I': case 'i': { - int (*f)() = func; - ret.i = f(); + int (*f)(DLSTACK_PROTO) = func; + ret.i = f(DLSTACK_ARGS); }; break; case 'L': case 'l': { - long (*f)() = func; - ret.l = f(); + long (*f)(DLSTACK_PROTO) = func; + ret.l = f(DLSTACK_ARGS); }; break; case 'F': case 'f': { - float (*f)() = func; - ret.f = f(); + float (*f)(DLSTACK_PROTO) = func; + ret.f = f(DLSTACK_ARGS); }; break; case 'D': case 'd': { - double (*f)() = func; - ret.d = f(); + double (*f)(DLSTACK_PROTO) = func; + ret.d = f(DLSTACK_ARGS); }; break; case 'S': case 's': { - char * (*f)() = func; - ret.s = f(); + char * (*f)(DLSTACK_PROTO) = func; + ret.s = f(DLSTACK_ARGS); }; break; default: FREE_ARGS; rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]); - }; - }; + } + } + } #else switch(ftype){ #include "call.func" |