Author Topic: Can gcc process __stdcall properly ?  (Read 17482 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: cpp
#ifdef __cplusplus
extern "C" {
#endif   // __cplusplus

int defaultCall(int param);
int __cdecl cdeclCall(int param);
int __stdcall stdCall(int param);
int __attribute__((stdcall)) attrStdCall(int param);

#ifdef __cplusplus
}
#endif   //__cplusplus

int main()
{
   int value = 0x55aa;

   value = stdCall(value);
   value = cdeclCall(value);
   value = defaultCall(value);
   value = attrStdCall(value);

   return value;
}

And I compile this file to generate the ASM code as followed:
Code: asm
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
movl $21930, -4(%ebp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call _stdCall@4
subl $4, %esp                ; delete the argument in stack ?
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call _cdeclCall               ; caller doesn't cleans up the stack ?
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call _defaultCall             ; default calling specification is C-Type ?
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call _attrStdCall@4
subl $4, %esp
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
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
_cdeclCall:
movl 4(%esp), %eax
ret
_stdCall@4:
movl 4(%esp), %eax
ret $4
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
push ebx
mov ebx,21930
push dword ebx
call _stdCall@4
mov ebx,eax
push dword ebx
call _cdeclCall
pop ecx
mov ebx,eax
push dword ebx
call _defaultCall
pop ecx
mov ebx,eax
@4:
pop ebx
ret
« 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.