All tests are compiled with the following GCC command-line:
gcc -S -O test.c
The C source file is:
int
function(int ac, char *av[])
{
char buf[16];
if (ac < 2)
return 0;
strcpy(buf, av[1]);
return 1;
}
int
main(int ac, char *av[])
{
function(ac, av);
return 0;
}
Expectation, GCC 2.8.1 and GCC 2.95.3
The expectation, GCC 2.8.1 and GCC 2.95.3 assembly versions are the same as in the previous article. The stack frames are therefore identical too.
GCC 3.4.6
Fortunately, the assembly code generated by GCC 3.4.6 is far less puzzling when the C source code stands in a mere function instead of main(). Actually, the code is nearly identical to the one generated by GCC 2.95.3. The stack pointer has been aligned in the main() function on 16 bytes boundary.
function:
pushl %ebp
movl %esp, %ebp
subl $24, %esp /* Alloc a 24 bytes buffer */
movl $0, %eax
cmpl $1, 8(%ebp)
jle .L1
subl $8, %esp /* Alloc an unused 8 bytes */
/* buffer */
movl 12(%ebp), %eax
pushl 4(%eax)
leal -24(%ebp), %eax /* The 24 bytes buffer is */
/* used for strcpy() */
pushl %eax
call strcpy
movl $1, %eax
.L1:
leave
ret
The corresponding stack frame, similar to the GCC 2.95.3 one but the entire 24 bytes buffer is provided to strcpy().
| av |
| ac |
| ret |
ebp-> | sebp |
|/ / / / | ^
| / / / /| |
|/ / / / | |
| / / / /| | buf, 24 bytes wide
|/ / / / | |
| / / / /| v
|\\\\\\\\| ^
|\\\\\\\\| v 8 unused bytes
| av[1] |
esp-> | &buf |
GCC 4.2.1
Astonishingly, GCC 4.2.1 does not keep with 16 bytes alignment, although it seemed to do so in the main() function.
function:
pushl %ebp
movl %esp, %ebp
subl $24, %esp /* Alloc a 24 bytes buffer */
movl $0, %eax
cmpl $1, 8(%ebp)
jle .L4
movl 12(%ebp), %edx
movl 4(%edx), %eax
movl %eax, 4(%esp) /* Fake push */
leal -16(%ebp), %eax /* A 16 bytes buffer is */
/* used for strcpy() */
movl %eax, (%esp) /* Fake push */
call strcpy
movl $1, %eax
.L4:
leave
ret
And now the stack frame:
| av |
| ac |
| ret |
ebp-> | sebp |
|/ / / / | ^ ^
| / / / /| | |
|/ / / / | | | buf, 16 bytes wide
| / / / /| | v
| av[1] | |
esp-> | &buf | v
The stack frame looks exactly like the expectation. One thing worth noting however is that GCC 4.2.1 always uses peculiar code for arguments storage. Instead of using the push instruction, it reserves space for arguments of further function calls in the same time as local variables are allocated. Arguments are the stored relative to %esp.
No comments:
Post a Comment