Reputation: 187
There are two simple C source files. The first is mainswap.c:
void swap(int *x, int *y);
int main()
{
int a, b;
a = 5;
b = 44;
swap(&a, &b);
return 0;
}
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
The other is mainfoobar.c:
int bar(int x, int y)
{
int z = x + y;
return z;
}
int foo(int a, int b)
{
return bar(a, b);
}
int main(void)
{
foo(2, 3);
return 0;
}
I got the relocatable object files of both. And I found that the gcc does something about alignment for the stack frame of function main
in mainswap.c
, meanwhile gcc does not do explicitly for the function main
in mainfoobar.c
.
The main of mainswap.c:
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $5, 24(%esp)
movl $44, 28(%esp)
leal 28(%esp), %eax
movl %eax, 4(%esp)
leal 24(%esp), %eax
movl %eax, (%esp)
call swap
movl $0, %eax
leave
ret
The main of mainfoobar.c:
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $3, 4(%esp)
movl $2, (%esp)
call foo
movl $0, %eax
leave
ret
I know the intention of andl $-16, %esp
and subl $32, %esp
. The same gcc version, the same options, the same computer, the only difference is the C source files. My question is why does gcc treat the two main functions differently, what is behind this phenomenon?
In addition, the version of gcc I used is:
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright © 2011 Free Software Foundation, Inc.
By the way, in function main
of mainswap.c, I think that subl $16, %esp
will also satisfy the alignment and the demand of use, why does gcc waste 16 bytes?
Upvotes: 0
Views: 151
Reputation: 17956
It appears you compiled both of these without optimization enabled. That explains some of the behavior you're seeing, as in that mode GCC processes the file top to bottom, typically, and doesn't try to inline or optimize much across functions. But, it will act on everything it knows when it arrives at a function.
In your two programs, main
appears either before or after the function it calls. That seems to be the key here.
If you change mainfoobar.c to look like this:
int main(void)
{
foo(2, 3);
return 0;
}
int bar(int x, int y)
{
int z = x + y;
return z;
}
int foo(int a, int b)
{
return bar(a, b);
}
you'll see a similar stack alignment operation in both versions' output. I suspect the difference between the two is whether the compiler has seen the callee yet at the point it reaches main
during code generation. When main
comes first, it generates a more conservative stack frame than when main
comes after all callees.
Apparently with the advent of SSE, GCC's 32-bit x86 ABI now requires 16-byte alignment across function call boundaries, unless it can prove otherwise. I'm not sure how strict that is. And, as the above example illustrates, GCC relaxes the alignment when it can prove the stricter alignment isn't necessary.
With a quick googling, I found this link that discusses some of the issue and gives a few other pointers. Yeah, it's a bug report on FreeBASIC, but it touches directly on this issue.
Upvotes: 1