bug-gnulib
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]