I have been trying to get some work done on a class returned by CreateTextServices, but the differences between windows' stdcall and linux' are giving me a few headaches. right now I've done it pretty much like this:
/* These macros are taken from wine/dlls/msvcrt/cpp.c */ #ifdef __i386__ /* thiscall functions are i386-specific */
#define THISCALL(func) __thiscall_ ## func #define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func) #define DEFINE_THISCALL_WRAPPER(func) \ extern void THISCALL(func)(); \ __ASM_GLOBAL_FUNC(__thiscall_ ## func, \ "popl %eax\n\t" \ "pushl %ecx\n\t" \ "pushl %eax\n\t" \ "jmp " __ASM_NAME(#func) ) #else /* __i386__ */
#define THISCALL(func) func #define THISCALL_NAME(func) __ASM_NAME(#func) #define DEFINE_THISCALL_WRAPPER(func) /* nothing */
#endif /* __i386__ */
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSendMessage); static HRESULT __stdcall fnTextSrv_TxSendMessage(ITextServices *iface, UINT msg, WPARAM wparam, LPARAM lparam, LRESULT* plresult) { .... }
static const ITextServicesVtbl textservices_Vtbl = { fnTextSrv_QueryInterface, fnTextSrv_AddRef, fnTextSrv_Release, THISCALL(fnTextSrv_TxSendMessage), ... };
This works, however it is not clean, it gives me 2 compiler warnings: 1: fnTextServ_TxSendMessage defined but not used 2: initialisation from incompatible pointer type (in the vtable)
I wonder how I can do this cleaner (Meaning no compiler warnings without ugly hacks). Also I would like to know how to call a function like __thiscall_fnTextSrv_TxSendMessage, because some methods I need are implemented in windows' stdcall. And I would like to know wether include/textserv.h needs to be adjusted now that I know they are not WINAPI.
On Tue, Jul 05, 2005 at 07:42:23PM +0200, Maarten Lankhorst wrote:
I have been trying to get some work done on a class returned by CreateTextServices, but the differences between windows' stdcall and linux' are giving me a few headaches. right now I've done it pretty much like this:
/* These macros are taken from wine/dlls/msvcrt/cpp.c */ #ifdef __i386__ /* thiscall functions are i386-specific */
#define THISCALL(func) __thiscall_ ## func #define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func) #define DEFINE_THISCALL_WRAPPER(func) \ extern void THISCALL(func)(); \ __ASM_GLOBAL_FUNC(__thiscall_ ## func, \ "popl %eax\n\t" \ "pushl %ecx\n\t" \ "pushl %eax\n\t" \ "jmp " __ASM_NAME(#func) ) #else /* __i386__ */
#define THISCALL(func) func #define THISCALL_NAME(func) __ASM_NAME(#func) #define DEFINE_THISCALL_WRAPPER(func) /* nothing */
#endif /* __i386__ */
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSendMessage); static HRESULT __stdcall fnTextSrv_TxSendMessage(ITextServices *iface, UINT msg, WPARAM wparam, LPARAM lparam, LRESULT* plresult) { .... }
static const ITextServicesVtbl textservices_Vtbl = { fnTextSrv_QueryInterface, fnTextSrv_AddRef, fnTextSrv_Release, THISCALL(fnTextSrv_TxSendMessage), ... };
This works, however it is not clean, it gives me 2 compiler warnings: 1: fnTextServ_TxSendMessage defined but not used
You can mark it as used with a __GNUC__ ifdef... like this:
#ifdef __GNUC__ __attribute__((used)) #endif static HRESULT __stdcall fnTextSrv_TxSendMessage(ITextServices *iface,
2: initialisation from incompatible pointer type (in the vtable)
Hmm, unclear. You would need to change the extern void THISCALL(func)(); to be the correct prototype.
__typeof__() games might not work.
I wonder how I can do this cleaner (Meaning no compiler warnings without ugly hacks). Also I would like to know how to call a function like __thiscall_fnTextSrv_TxSendMessage, because some methods I need are implemented in windows' stdcall. And I would like to know wether include/textserv.h needs to be adjusted now that I know they are not WINAPI.
Adding "thiscall" to gcc would perhaps help in the long run ... :/ Fun fun fun...
Ciao, Marcus
On 05.07.2005 21:30, Marcus Meissner wrote:
2: initialisation from incompatible pointer type (in the vtable)
Hmm, unclear. You would need to change the extern void THISCALL(func)(); to be the correct prototype.
But otoh, the vtable types really are wrong (the methods just aren't stdcall).
Perhaps make the opposite change, just turn all vtable entries into type "void (*foo);". The vtable entries wouldn't be suitable for calling from C anyway, as you'd need to wrap them for "thiscall" again...
Adding "thiscall" to gcc would perhaps help in the long run ... :/ Fun fun fun...
Although, 'thiscall' is a C++ calling convention, would it make that much sense in a C context?
-f.r.
Marcus Meissner wrote:
I wonder how I can do this cleaner (Meaning no compiler warnings without ugly hacks). Also I would like to know how to call a function like __thiscall_fnTextSrv_TxSendMessage, because some methods I need are implemented in windows' stdcall. And I would like to know wether include/textserv.h needs to be adjusted now that I know they are not WINAPI.
Adding "thiscall" to gcc would perhaps help in the long run ... :/ Fun fun fun...
Considering that gcc already knows regparm and we just need regparm(1) with ecx instead eax hacking in "thiscall" for C code shouldn't be too hard I think.
But since this would be a very Wine-specific hack I doubt it would get into GCC. The right way would probably to extend the regparm attribute to allow specifying arbitrary registers...
Felix
On Tue, Jul 05, 2005 at 10:16:08PM +0200, Felix Nawothnig wrote:
Marcus Meissner wrote:
I wonder how I can do this cleaner (Meaning no compiler warnings without ugly hacks). Also I would like to know how to call a function like __thiscall_fnTextSrv_TxSendMessage, because some methods I need are implemented in windows' stdcall. And I would like to know wether include/textserv.h needs to be adjusted now that I know they are not WINAPI.
Adding "thiscall" to gcc would perhaps help in the long run ... :/ Fun fun fun...
Considering that gcc already knows regparm and we just need regparm(1) with ecx instead eax hacking in "thiscall" for C code shouldn't be too hard I think.
But since this would be a very Wine-specific hack I doubt it would get into GCC. The right way would probably to extend the regparm attribute to allow specifying arbitrary registers...
No, we could just propose thiscall to the gcc folks.
In short and mid term this needs to be fixed with above hack or so.
CIao, Marcus
Marcus Meissner wrote:
Adding "thiscall" to gcc would perhaps help in the long run ... :/ Fun fun fun...
Considering that gcc already knows regparm and we just need regparm(1) with ecx instead eax hacking in "thiscall" for C code shouldn't be too hard I think. But since this would be a very Wine-specific hack I doubt it would get into GCC. The right way would probably to extend the regparm attribute to allow specifying arbitrary registers...
No, we could just propose thiscall to the gcc folks.
We can propose whatever we want - that's no argument at all. :-)
My point is, as pointed out before, "thiscall" doesn't really make sense in C context. The only use for this would be binary-compatibility with MSVC C++ when using C - even more since true MSVC C++ compatiblity would still be missing.
I don't think such an application-specific hack belongs into a compiler - especially if it can be avoided by extending an already existing feature (regparm) in a generic way.
This would also allow binary-compatibility to the ABI of FooSoft which thought it would be nifty to pass the first argument in EDX.
In short and mid term this needs to be fixed with above hack or so.
You mean the macros we are using right now? Sure.
Felix
On Tue, Jul 05, 2005 at 10:16:08PM +0200, Felix Nawothnig wrote:
Marcus Meissner wrote:
I wonder how I can do this cleaner (Meaning no compiler warnings without ugly hacks). Also I would like to know how to call a function like __thiscall_fnTextSrv_TxSendMessage, because some methods I need are implemented in windows' stdcall. And I would like to know wether include/textserv.h needs to be adjusted now that I know they are not WINAPI.
Adding "thiscall" to gcc would perhaps help in the long run ... :/ Fun fun fun...
Considering that gcc already knows regparm and we just need regparm(1) with ecx instead eax hacking in "thiscall" for C code shouldn't be too hard I think.
But since this would be a very Wine-specific hack I doubt it would get into GCC. The right way would probably to extend the regparm attribute to allow specifying arbitrary registers...
On second thought... What about abusing the "regparm(3)" attribute for this.
It gets eax, edx, ecx, stackparam1, stackparam2, ...
So what about using a construct like this (cloaked in some macros)?
#define THISCALL0(name,this) __thiscall_#name(int unused_eax,int unused_edx, void *this) #define THISCALL1(name,this,p1) __thiscall_#name(int unused_eax,int unused_edx, void *this, int p1)
---------compile with gcc -S to check assembler ------------ extern void g(int);
__attribute__((__regparm__(3),__stdcall__)) void f(int unused_eax,int unused_edx, int this, int p1, int p2, int p3) { g(this); g(p1); g(p2); g(p3); } ---------compile with gcc -S to check assembler ------------
Evil, yes.
Ciao, Marcus
Marcus Meissner wrote:
On second thought... What about abusing the "regparm(3)" attribute for this.
It gets eax, edx, ecx, stackparam1, stackparam2, ...
So what about using a construct like this (cloaked in some macros)?
#define THISCALL0(name,this) __thiscall_#name(int unused_eax,int unused_edx, void *this) #define THISCALL1(name,this,p1) __thiscall_#name(int unused_eax,int unused_edx, void *this, int p1)
I'm sure you meant to include the regparm attribute in the macro? :)
I admit that it looks better than the current hack - but it's still a hack... I'd still prefer a long-term solution in GCC.
Felix
Marcus Meissner schreef:
On Tue, Jul 05, 2005 at 10:16:08PM +0200, Felix Nawothnig wrote:
Marcus Meissner wrote:
I wonder how I can do this cleaner (Meaning no compiler warnings without ugly hacks). Also I would like to know how to call a function like __thiscall_fnTextSrv_TxSendMessage, because some methods I need are implemented in windows' stdcall. And I would like to know wether include/textserv.h needs to be adjusted now that I know they are not WINAPI.
Adding "thiscall" to gcc would perhaps help in the long run ... :/ Fun fun fun...
Considering that gcc already knows regparm and we just need regparm(1) with ecx instead eax hacking in "thiscall" for C code shouldn't be too hard I think.
But since this would be a very Wine-specific hack I doubt it would get into GCC. The right way would probably to extend the regparm attribute to allow specifying arbitrary registers...
On second thought... What about abusing the "regparm(3)" attribute for this.
It gets eax, edx, ecx, stackparam1, stackparam2, ...
So what about using a construct like this (cloaked in some macros)?
#define THISCALL0(name,this) __thiscall_#name(int unused_eax,int unused_edx, void *this)
#define THISCALL1(name,this,p1) __thiscall_#name(int unused_eax,int unused_edx, void *this, int p1)
It looks evil, and those functions are not exactly what I want, because I need them in a vtable, which requires them to be something like HRESULT ... fnTextServ_blah(ITextServices *iface, args), I could recast those functions, but that is not exactly a 'clean' solution, adding 'thiscall' to gcc would definitely help a lot. Until gcc supports thiscall, I think it would be easier to just fix the macro's I already have and set attribute 'used' to avoid compiler warnings. But I still wonder what I have to do to call a 'thiscall' function, since I probably need it in ITextHost.
Maarten Lankhorst
On 06.07.2005 00:54, Maarten Lankhorst wrote:
But I still wonder what I have to do to call a 'thiscall' function, since I probably need it in ITextHost.
Probably more assembly ;)
'Thiscall' expects 'this' in ecx, so perhaps create an stdcall wrapper function that contains some assembly to pop the first argument (ie this) off the stack, load it into ecx and call the 'thiscall' method...
-f.r.
Maarten Lankhorst wrote:
It looks evil, and those functions are not exactly what I want, because I need them in a vtable, which requires them to be something like HRESULT ... fnTextServ_blah(ITextServices *iface, args), I could recast those functions, but that is not exactly a 'clean' solution, adding 'thiscall' to gcc would definitely help a lot. Until gcc supports thiscall, I think it would be easier to just fix the macro's I already have and set attribute 'used' to avoid compiler warnings. But I still wonder what I have to do to call a 'thiscall' function, since I probably need it in ITextHost.
With those (evil) macros you could do:
#define CALL_THISCALL0(name,this) __thiscall_#name(0,0,this) #define CALL_THISCALL1(name,this,p1) __thiscall_#name(0,0,this,p1)
If you wanna use the same technique as used in MSVCRT you would do something like:
#define STDCALL(func) __stdcall_ ## func #define STDCALL_NAME(func) __ASM_NAME("__stdcall_" #func) #define DEFINE_STDCALL_WRAPPER(func) \ extern void STDCALL(func)(); \ __ASM_GLOBAL_FUNC(__stdcall_ ## func, \ "popl %eax\n\t" \ "popl %ecx\n\t" \ "pushl %eax\n\t" \ "jmp " __ASM_NAME(#func) )
Now you can do:
void WINAPI foo(int a, int b);
DEFINE_STDCALL_WRAPPER(foo);
int bar() { __stdcall_foo(1,2,3); }
Thinking up better macro-names is left as an exercise for the reader. :)
Felix
To suppress warnings from my thiscall wrapped stuff, I came up with this solution, playing around a little with #define's:
#ifdef __i386__ /* thiscall functions are i386-specific */
#ifdef __GNUC__ /* GCC erroneously warns that the newly wrapped function * isn't used, lets help it out of it's thinking */ #define SUPPRESS_NOTUSED __attribute__((used)) #else #define SUPPRESS_NOTUSED #endif /* __GNUC__ */
#define WRAP_THISCALL(type, func, parm) \ extern type func parm; \ __ASM_GLOBAL_FUNC( func, \ "popl %eax\n\t" \ "pushl %ecx\n\t" \ "pushl %eax\n\t" \ "jmp " __ASM_NAME("__wrapped_" #func) ); \ SUPPRESS_NOTUSED static type __wrapped_ ## func parm #else #define WRAP_THISCALL(functype, function, param) \ functype function param #endif
Declaration of function is now like this: WRAP_THISCALL(HRESULT __stdcall, fnTextSrv_TxSendMessage, (ITextServices *iface, UINT msg, WPARAM wparam, LPARAM lparam, LRESULT* plresult)) { .... }
In the vtable I can now just use the function names as I declared them n the wrap.
Lets hope julliard forgives me.
Maarten