Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

__cdecl results in larger executable than __stdcall?

I found this:

Because the stack is cleaned by the called function, the __stdcall calling convention creates smaller executables than __cdecl, in which the code for stack cleanup must be generated for each function call.

Suppose I got 2 functions:

void __cdecl func1(int x)
{
    //do some stuff using x
}

void __stdcall func2(int x, int y)
{
    //do some stuff using x, y
}

and here in the main():

int main()
{
    func1(5);
    func2(5, 6);
}

IMO, it is main()'s responsibility to clean up the stack of the call to func1(5), and func2 will clean up the stack of the call to func2(5,6), right?

Four questions:

1.For the call to func1 in main(), it's main's responsibility to clean up the stack, so will compiler insert some code (code to clean up the stack) before and after the call to func? Like this:

int main()
{
    before_call_to_cdecl_func(); //compiler generated code for stack-clean-up of cdecl-func-call
    func1(5);
    after_call_to_cdecl_func(); //compiler generated code for stack-clean-up of cdecl-func-call

    func2(5, 6);
}

2.For the call to func2 in main(), it's func2's own job to clean up the stack, so I presume, no code will be inserted in main() before or after the call to func2, right?

3.Because func2 is __stdcall, so I presume, compiler will automatically insert code (to clean up the stack) like this:

void __stdcall func1(int x, int y)
{
    before_call_to_stdcall_func(); //compiler generated code for stack-clean-up of stdcall-func-call
    //do some stuff using x, y
    after_call_to_cdecl_func(); //compiler generated code for stack-clean-up of stdcall-func-call
}

I presume right?

4.Finally, back to the quoted words, why __stdcall results in smaller executable than __cdecl? And there is no such a thing as __stdcall in linux, right? Does it means linux elf will be always larger than exe in win?

like image 885
Alcott Avatar asked Feb 07 '12 08:02

Alcott


1 Answers

  1. It'll only insert code after the call, which is to reset the stack pointer, so long as there where call arguments.*
  2. __stdcall generates no cleanup code at the call site, however, it should be noted that compilers can accrue stack cleanup from multiple __cdecl calls into one cleanup, or it can delay the cleanup to prevent pipeline stalls.
  3. Ignoring the inverted order in this example, no, it'll only insert code to cleanup the __cdecl function, setting up of function arguments is something different (different compilers generate/prefer different methods).
  4. __stdcall was more a windows thing, see this. the size of the binary depends on the number of calls to the __cdecl funcs, more calls means more clean up code, where as __stdcall has only 1 singular instance of cleanup code. however, you shouldn't see that much size increase, as at most you have a few bytes per call.

*Its important to distinguish between cleanup and setting up call parameters.

like image 81
Necrolis Avatar answered Sep 30 '22 07:09

Necrolis