Tietew です。 On Mon, 20 Oct 2003 23:53:22 +0900 In article <20031020232800.AA1F.ARTONX / yahoo.co.jp> [[ruby-list:38619] dl and win32 API call] arton <artonx / yahoo.co.jp> wrote: > win32に特化した問題ですが、ruby-win32が止まっているようなのでこちらに振 > ります。 まだ止まってますか? > 主題:ruby-1.8.0添付のdlを利用してWIN32 APIを呼び出すとスタックポインタ > がずれる。元の話題はhttp://www.tietew.jp/beckrb/msg00113.html です。 > 詳細:WIN32 APIでは、引数のスタックからのポップを呼ばれた側が実行する。 > しかし、dlは関数呼出し後に引数をスタックからポップする。そのため、引数の > 分だけ余分にスタックポインタがポップされてしまう。 問題提起拾ってもらったのにほっぽってしまってすみません。 上記に関連して,MSVC のランタイムスタックチェックをすり抜けられ るパッチを作ってみました。(-RTCs を付けていても abort しない) mswin32 でしか確認できてないのですが,呼び出しが終わった後,全て のレジスタが正常になっていることを確認しています。 i686-linux でのコンパイルでも,dl.so の make test は正常に終了し ました。 alloca を呼ぶとスタックフレームが保存されるというコンパイラの仕 様をアテにしているので,他の環境でも問題ないか検証をお願いしたい です。 Index: ext/Win32API/Win32API.c =================================================================== RCS file: /src/ruby/ext/Win32API/Win32API.c,v retrieving revision 1.19 diff -p -u -2 -r1.19 Win32API.c --- ext/Win32API/Win32API.c 13 Aug 2003 04:52:35 -0000 1.19 +++ ext/Win32API/Win32API.c 21 Nov 2003 05:13:24 -0000 @@ -138,4 +138,22 @@ Win32API_initialize(self, dllname, proc, } +#ifdef __MSVC_RUNTIME_CHECKS +# pragma runtime_checks("s", off) +#endif +#ifdef _MSC_VER +__declspec(noinline) +#endif +static unsigned long +CallApiFunction(ApiFunction, param) + FARPROC ApiFunction; + struct { unsigned long params[16]; } param; +{ + volatile char *guard = ALLOCA_N(char, 1); /* guard stack pointer */ + return ApiFunction(param); +} +#ifdef __MSVC_RUNTIME_CHECKS +# pragma runtime_checks("s", restore) +#endif + static VALUE Win32API_Call(argc, argv, obj) @@ -189,5 +207,5 @@ Win32API_Call(argc, argv, obj) } - ret = ApiFunction(param); + ret = CallApiFunction(ApiFunction, param); switch (FIX2INT(obj_export)) { Index: ext/dl/dl.h =================================================================== RCS file: /src/ruby/ext/dl/dl.h,v retrieving revision 1.8 diff -p -u -2 -r1.8 dl.h --- ext/dl/dl.h 7 Nov 2002 16:42:07 -0000 1.8 +++ ext/dl/dl.h 21 Nov 2003 05:13:24 -0000 @@ -171,4 +171,5 @@ #elif defined(USE_DLSTACK) # define DLSTACK +# define DLSTACK_GUARD # define DLSTACK_METHOD "dl" # define DLSTACK_PROTO long,long,long,long,long,\ Index: ext/dl/sym.c =================================================================== RCS file: /src/ruby/ext/dl/sym.c,v retrieving revision 1.21 diff -p -u -2 -r1.21 sym.c --- ext/dl/sym.c 8 Nov 2003 13:32:07 -0000 1.21 +++ ext/dl/sym.c 21 Nov 2003 05:13:24 -0000 @@ -353,4 +353,88 @@ rb_dl_win32_set_last_error(VALUE self, V #endif +#ifdef DLSTACK_GUARD +# ifdef __MSVC_RUNTIME_CHECKS +# pragma runtime_checks("s", off) +# endif +#ifdef _MSC_VER +__declspec(noinline) +#endif +static int +rb_dlsym_guardcall(char type, ANY_TYPE *ret, long *stack, void *func) +{ + volatile char *guard = ALLOCA_N(char, 1); /* guard stack pointer */ + switch(type){ + case '0': + { + void (*f)(DLSTACK_PROTO) = func; + f(DLSTACK_ARGS); + } + break; + case 'P': + case 'p': + { + void * (*f)(DLSTACK_PROTO) = func; + ret->p = f(DLSTACK_ARGS); + } + break; + case 'C': + case 'c': + { + char (*f)(DLSTACK_PROTO) = func; + ret->c = f(DLSTACK_ARGS); + } + break; + case 'H': + case 'h': + { + short (*f)(DLSTACK_PROTO) = func; + ret->h = f(DLSTACK_ARGS); + } + break; + case 'I': + case 'i': + { + int (*f)(DLSTACK_PROTO) = func; + ret->i = f(DLSTACK_ARGS); + } + break; + case 'L': + case 'l': + { + long (*f)(DLSTACK_PROTO) = func; + ret->l = f(DLSTACK_ARGS); + } + break; + case 'F': + case 'f': + { + float (*f)(DLSTACK_PROTO) = func; + ret->f = f(DLSTACK_ARGS); + } + break; + case 'D': + case 'd': + { + double (*f)(DLSTACK_PROTO) = func; + ret->d = f(DLSTACK_ARGS); + } + break; + case 'S': + case 's': + { + char * (*f)(DLSTACK_PROTO) = func; + ret->s = f(DLSTACK_ARGS); + } + break; + default: + return 0; + } + return 1; +} +# ifdef __MSVC_RUNTIME_CHECKS +# pragma runtime_checks("s", restore) +# endif +#endif /* defined(DLSTACK_GUARD) */ + VALUE rb_dlsym_call(int argc, VALUE argv[], VALUE self) @@ -643,4 +727,10 @@ rb_dlsym_call(int argc, VALUE argv[], VA DLSTACK_END(sym->type); +#ifdef DLSTACK_GUARD + if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, func)) { + FREE_ARGS; + rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]); + } +#else /* defined(DLSTACK_GUARD) */ { switch( sym->type[0] ){ @@ -712,4 +802,5 @@ rb_dlsym_call(int argc, VALUE argv[], VA } } +#endif /* defubed(DLSTACK_GUARD) */ { ―[ Tietew ]―――――――――――――――――――――――――― メ : tietew / tietew.net / tietew / raug.net / tietew / masuclub.net ホペ: http://www.tietew.net/ Tietew Windows Lab. http://www.masuclub.net/ 鱒倶楽部 指紋: 26CB 71BB B595 09C4 0153 81C4 773C 963A D51B 8CAA