From: SourceForge.net <no...@so...> - 2004-05-20 22:35:21
|
Read and respond to this message at: https://sourceforge.net/forum/message.php?msg_id=2579358 By: dansofo MinGW calling conventions How does MinGW implement the parameters passing order for the calling conventions ? In the standard C calling convention (__cdecl), the parameters are pushed from right to left, and the caller must clear the stack after the call. In the other calling conventions (__stdcall, __pascal, etc), the parameters are pushed from left to right, and the called routine removes arguments from the stack. It is not clear how MinGW implements these conventions, particularly in the case of DLL calls. Suppose a .DLL with the following routine (compiled ie with CBuilder): __declspec(dllexport) long CALLING_CONVENTION FNTEST( long a, long b ) { return a - b; } (CALLING_CONVENTION may be __stdcall or __cdecl) If it is called from a MinGW program in the following way: typedef long (CALL_CONVENTION * TESTFN) (long, long); // Good coding to define parameters TESTFN FnPtr; FnPtr = (TESTFN) GetProcAddress ( hLib, "FNTEST" ); // or "_FNTEST" lResult = FnPtr( 10, 7 ); // or (* FnPtr)(10, 7) the arguments are received by the DLL routine in the CORRECT order (a, b), whether: a) CALL_CONVENTION in the PROGRAM is empty, __stdcall or __cdecl !!! b) the called routine in the .DLL is defined as __stdcall or __cdecl !!! I don't understand how this is possible !!! (And my program should crash if there is a mismatch between the calling and the called conventions !) I was puzzled by this behavior when, for a special purpose, I had to push the arguments MYSELF: typedef long (* TESTFN) (); TESTFN FnPtr; long a=10, b=7; FnPtr = (TESTFN) GetProcAddress ( hLib, "FNTEST" ); // or "_FNTEST" __asm__ __volatile__ ( "movl %0, %%eax; pushl %%eax;" : /* no output */ :"r" (a) /* 0 input */ :"%eax" /* clobbered register */ ); __asm__ __volatile__ ( "movl %0, %%eax; pushl %%eax;" : /* no output */ :"r" (b) /* 0 input */ :"%eax" /* clobbered register */ ); // a & b are now on the stack lResult = FnPtr(); // or (* FnPtr)() In this case, the arguments are received in the REVERSE order (b,a), whether the called routine in the .DLL is defined as __stdcall (a,b order) or __cdecl (b,a order ) !!! This is amazing, because the equivalent with other compilers (MSC, Borland) works as expected... NOTE: I had to use asm because the trick to push parameters using a __pascal routine (see David Cortesi on OS2 programming and Andrew Schulman PC Mag 11,16), that works with other compilers, doesn't work with MinGW: void __pascal push() {} typedef void (__pascal * PUSHLONG)( long ); PUSHLONG pushFn = (PUSHLONG) push; pushFn( a ); pushFn( b ); // a & b are now on the stack lResult = FnPtr(); // or (* FnPtr)() With MinGW, no argument is passed to the called routine ! (while it is OK with other compilers) TIA for any light on this matter. Daniel ______________________________________________________________________ You are receiving this email because you elected to monitor this forum. To stop monitoring this forum, login to SourceForge.net and visit: https://sourceforge.net/forum/unmonitor.php?forum_id=7134 |