[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: C++ aliases in <netdb.h>
From: |
Pedro Alves |
Subject: |
Re: C++ aliases in <netdb.h> |
Date: |
Mon, 19 Dec 2016 12:10:27 +0000 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 |
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 'address@hidden' 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 <address@hidden>:
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 <address@hidden>
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