Author Topic: Can gcc process __stdcall properly ?  (Read 14466 times)

Offline kingfox

  • Multiple posting newcomer
  • *
  • Posts: 41
Can gcc process __stdcall properly ?
« on: October 24, 2006, 04:12:02 pm »
I get the description of __stdcall as this: "does not generate underscores prefix of function name, preserve case, called function pops the stack, and caller pushes parameters right to left". And the description of __cdecl as: "__cdecl modifier to declare a variable or a function using the C-style naming conventions (case-sensitive, with a leading underscore appended), it affects how the parameters are passed (parameters are pushed right to left, and the caller cleans up the stack)".

I write a program to test how does gcc process __stdcall and __cdecl. The code is:
Code: C++
  1. #ifdef __cplusplus
  2. extern "C" {
  3. #endif   // __cplusplus
  4.  
  5. int defaultCall(int param);
  6. int __cdecl cdeclCall(int param);
  7. int __stdcall stdCall(int param);
  8. int __attribute__((stdcall)) attrStdCall(int param);
  9.  
  10. #ifdef __cplusplus
  11. }
  12. #endif   //__cplusplus
  13.  
  14. int main()
  15. {
  16.    int value = 0x55aa;
  17.  
  18.    value = stdCall(value);
  19.    value = cdeclCall(value);
  20.    value = defaultCall(value);
  21.    value = attrStdCall(value);
  22.  
  23.    return value;
  24. }
  25.  

And I compile this file to generate the ASM code as followed:
Code: ASM
  1. _main:
  2.         pushl   %ebp
  3.         movl    %esp, %ebp
  4.         subl    $24, %esp
  5.         andl    $-16, %esp
  6.         movl    $0, %eax
  7.         addl    $15, %eax
  8.         addl    $15, %eax
  9.         shrl    $4, %eax
  10.         sall    $4, %eax
  11.         movl    %eax, -8(%ebp)
  12.         movl    -8(%ebp), %eax
  13.         call    __alloca
  14.         call    ___main
  15.         movl    $21930, -4(%ebp)
  16.         movl    -4(%ebp), %eax
  17.         movl    %eax, (%esp)
  18.         call    _stdCall@4
  19.         subl    $4, %esp                ; delete the argument in stack ?
  20.         movl    %eax, -4(%ebp)
  21.         movl    -4(%ebp), %eax
  22.         movl    %eax, (%esp)
  23.         call    _cdeclCall               ; caller doesn't cleans up the stack ?
  24.         movl    %eax, -4(%ebp)
  25.         movl    -4(%ebp), %eax
  26.         movl    %eax, (%esp)
  27.         call    _defaultCall             ; default calling specification is C-Type ?
  28.         movl    %eax, -4(%ebp)
  29.         movl    -4(%ebp), %eax
  30.         movl    %eax, (%esp)
  31.         call    _attrStdCall@4
  32.         subl    $4, %esp
  33.         movl    %eax, -4(%ebp)
  34.         movl    -4(%ebp), %eax
  35.         leave
  36.         ret

Please look at the comments in asm code. When calling a __stdcall modified function, gcc generate the code to clean up the arguments in stack. But when calling a __cdecl modified function, gcc doesn't generate the code to clean up the arguments in stack. Is't a bug of gcc for windows ?

BTW, my compiler is MinGW32 GCC 3.4.4.

[attachment deleted by admin]
« Last Edit: October 24, 2006, 04:17:53 pm by kingfox »

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Can gcc process __stdcall properly ?
« Reply #1 on: October 24, 2006, 04:31:13 pm »
According to its docs, gcc implements fastcall and cdecl alike. That is not what your code looks like, though.
However, it's rather unlikely that anyone here will be able to help you... Danny Smith or anyone else from the
MinGW team might be a better contact for that.

Anyway, what is the exact purpose of this?
movl   %eax, -4(%ebp)
movl   -4(%ebp), %eax


Is it just me or does that look a bit weird...?
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

Offline kingfox

  • Multiple posting newcomer
  • *
  • Posts: 41
Re: Can gcc process __stdcall properly ?
« Reply #2 on: October 24, 2006, 04:51:38 pm »
Thanks for your reply.

Anyway, what is the exact purpose of this?
movl   %eax, -4(%ebp)
movl   -4(%ebp), %eax


Is it just me or does that look a bit weird...?

I think "movl   %eax, -4(%ebp)" will assign the return value of called function to the local variable "value". And "movl   -4(%ebp), %eax" retrieve the value in "value" to EAX register. At the next statement "movl      %eax, (%esp)" put the value of EAX into stack as the input argument. I am not familiar with the assembly language, so above is only my suppose.

Offline severach

  • Multiple posting newcomer
  • *
  • Posts: 44
Re: Can gcc process __stdcall properly ?
« Reply #3 on: October 30, 2006, 04:57:32 am »
Look at the assembly code for each function:
Code: ASM
  1. _cdeclCall:
  2.         movl    4(%esp), %eax
  3.         ret
  4. _stdCall@4:
  5.         movl    4(%esp), %eax
  6.         ret     $4
  7.  
There is no doubt that both conform to the calling conventions so the calling code must conform or it would not work.

You are being confused by a compiler that produces code so good that it's hard to recognize what it's doing because you don't see the familiar constructs. Notice that the code you are calling "cleanup code" is subtracts, not adds as you would normally expect. This means that the compiler noticed that there were 4 calls in a row that all took the same parameters. Rather than wasting lots of time popping and pushing it decided to leave the parameter right there and fuss with the stack pointer to keep each function call correct. A cdecl call requires no fussing because the parameter is still where it was before. The stdcall function uses sub to undo what the "ret $4" did to get the parameter back in the right place.

Besides, most Win32 calls are stdcall. If stdcall didn't work right, MinGW wouldn't be any use for Win32 development. When in doubt, assume that the compiler is correct and you are not.

As always, I'm impressed by the quality of code that MinGW/GCC generates.

Perhaps the code from Pelles will look more familiar:
Code: ASM
  1. push ebx
  2. mov ebx,21930
  3. push dword ebx
  4. call _stdCall@4
  5. mov ebx,eax
  6. push dword ebx
  7. call _cdeclCall
  8. pop ecx
  9. mov ebx,eax
  10. push dword ebx
  11. call _defaultCall
  12. pop ecx
  13. mov ebx,eax
  14. @4:
  15. pop ebx
  16. ret
  17.  
« Last Edit: October 30, 2006, 05:21:38 am by severach »

Offline kingfox

  • Multiple posting newcomer
  • *
  • Posts: 41
Re: Can gcc process __stdcall properly ?
« Reply #4 on: October 30, 2006, 03:40:36 pm »
Thanks severach very much. Yes, I have a mistake about the direction of the stack of x86 because these months I'm developping a program running on a DSP which have a increasing stack.