On 12/17/2016 09:32 AM, Gisle Vanem wrote: > Pedro Alves wrote: > >> Can't see how that can run fine? The compiler will set up the call >> assuming cdecl convention, while the called function has stdcall >> convention. > > I would expect the 'reinterpret_cast<type>(::getaddrinfo)' to fix that. > Running the program shows that '__imp__getaddrinfo@16' gets the arguments > in the right order. So '__stdcall' must be in effect.
cdecl and stdcall pass the arguments in the same order. The difference is in who is responsible for cleaning up the stack (callee vs caller). E.g., with compiling the following with i686-w64-mingw32-g++ (cross compiled on Fedora here): ~~~~~~~~ typedef int (func_cdecl)(int a, int b, int c); typedef int (__stdcall func_stdcall)(int a, int b, int c); int __stdcall stdcall_func(int a, int b, int c) { return 0; } int cdecl_func(int a, int b, int c) { return 0; } void call_stdcall (void) { stdcall_func (1, 2, 3); } void call_stdcall_ptr_good (void) { func_stdcall *f = stdcall_func; f (1, 2, 3); } void call_stdcall_ptr_bad (void) { func_cdecl *f = reinterpret_cast<func_cdecl *> (stdcall_func); f (1, 2, 3); } void call_cdecl (void) { cdecl_func (1, 2, 3); } int main (void) { call_stdcall (); call_stdcall_ptr_good (); call_stdcall_ptr_bad (); call_cdecl (); return (0); } ~~~~~~~~ We see, for the stdcall_func/cdecl_func callees: 00401570 <__Z12stdcall_funciii@12>: 401570: 55 push %ebp 401571: 89 e5 mov %esp,%ebp 401573: b8 00 00 00 00 mov $0x0,%eax 401578: 5d pop %ebp 401579: c2 0c 00 ret $0xc 0040157c <__Z10cdecl_funciii>: 40157c: 55 push %ebp 40157d: 89 e5 mov %esp,%ebp 40157f: b8 00 00 00 00 mov $0x0,%eax 401584: 5d pop %ebp 401585: c3 ret Note the difference in the "ret" instruction. And for the calls that don't go through a function pointer, we see: 00401586 <__Z12call_stdcallv>: ... 4015a3: e8 c8 ff ff ff call 401570 <__Z12stdcall_funciii@12> 4015a8: 83 ec 0c sub $0xc,%esp ... Note the "sub 0xc", which matches the "@12". "call_cdecl" compiles to the exact same, except it doesn't have that sub instruction. And now the interesting part, compare what happens when calling through the good vs bad (i.e., reinterpret_cast) function pointers: 004015ae <__Z21call_stdcall_ptr_goodv>: 4015ae: 55 push %ebp 4015af: 89 e5 mov %esp,%ebp 4015b1: 83 ec 28 sub $0x28,%esp 4015b4: c7 45 f4 70 15 40 00 movl $0x401570,-0xc(%ebp) 4015bb: c7 44 24 08 03 00 00 movl $0x3,0x8(%esp) 4015c2: 00 4015c3: c7 44 24 04 02 00 00 movl $0x2,0x4(%esp) 4015ca: 00 4015cb: c7 04 24 01 00 00 00 movl $0x1,(%esp) 4015d2: 8b 45 f4 mov -0xc(%ebp),%eax 4015d5: ff d0 call *%eax 4015d7: 83 ec 0c sub $0xc,%esp 4015da: 90 nop 4015db: c9 leave 4015dc: c3 ret 004015dd <__Z20call_stdcall_ptr_badv>: 4015dd: 55 push %ebp 4015de: 89 e5 mov %esp,%ebp 4015e0: 83 ec 28 sub $0x28,%esp 4015e3: c7 45 f4 70 15 40 00 movl $0x401570,-0xc(%ebp) 4015ea: c7 44 24 08 03 00 00 movl $0x3,0x8(%esp) 4015f1: 00 4015f2: c7 44 24 04 02 00 00 movl $0x2,0x4(%esp) 4015f9: 00 4015fa: c7 04 24 01 00 00 00 movl $0x1,(%esp) 401601: 8b 45 f4 mov -0xc(%ebp),%eax 401604: ff d0 call *%eax 401606: 90 nop 401607: c9 leave 401608: c3 ret Note that the "bad" version misses the "sub $0xc,%esp". I.e., the compiled code assumes the function the function pointer points to is cdecl, which is incorrect. The reinterpret_cast does _not_ magically fix this. Thanks, Pedro Alves