GCC Array
by Mithrandir
While doing one homework I’ve observed one little known fact about gcc: declaring dynamic arrays as normal arays (like int a[n])
I’ve decided to investigate this a little and wrote this small code:</p
#include <stdio.h>
#include <stdlib.h>
int f(int n)
{
#ifdef EXT
int a[n];
#else
int *a=calloc(5, sizeof(a[0]));
#endif
a[2] = n;
return a[2];
}
int main()
{
printf("%d\n", f(5));
return 0;
}
Compiling this code, looking at file sizes and testing it we obtain the following:
mihai@keldon:/tmp$ gcc -Wall -Wextra 1.c -S -o 1a.s && gcc 1a.s && ls -lh 1a.s a.out && wc -l 1a.s && ./a.out
-rw-r--r-- 1 mihai mihai 786 2010-05-01 11:14 1a.s
-rwxr-xr-x 1 mihai mihai 9.0K 2010-05-01 11:14 a.out
50 1a.s
5
mihai@keldon:/tmp$ gcc -Wall -Wextra 1.c -S -o 1b.s -DEXT && gcc 1b.s && ls -lh 1b.s a.out && wc -l 1b.s && ./a.out
-rw-r--r-- 1 mihai mihai 2.0K 2010-05-01 11:15 1b.s
-rwxr-xr-x 1 mihai mihai 9.0K 2010-05-01 11:15 a.out
116 1b.s
5
Let’s look at the generated assembly in each of the two cases. For 1a.s (normal case) we have:
.file "1.c"
.text
.globl f
.type f, @function
f:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $4, 4(%esp)
movl $2, (%esp)
call calloc
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leal 8(%eax), %edx
movl 8(%ebp), %eax
movl %eax, (%edx)
movl -4(%ebp), %eax
addl $8, %eax
movl (%eax), %eax
leave
ret
.size f, .-f
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
movl $5, (%esp)
call f
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
movl $0, %eax
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",@progbits
The second file looks like this:
.file "1.c"
.text
.globl f
.type f, @function
f:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
pushl %ebx
subl $44, %esp
movl %gs:20, %eax
movl %eax, -20(%ebp)
xorl %eax, %eax
movl %esp, %eax
movl %eax, %edi
movl 8(%ebp), %esi
movl %esi, %eax
movl %eax, -56(%ebp)
movl $0, -52(%ebp)
movl -56(%ebp), %eax
andb $255, %ah
movl -52(%ebp), %edx
andl $15, %edx
movl %eax, -56(%ebp)
movl %edx, -52(%ebp)
movl -56(%ebp), %ecx
movl -52(%ebp), %ebx
shldl $5, %ecx, %ebx
sall $5, %ecx
movl %ecx, %eax
andb $255, %ah
movl %ebx, %edx
andl $15, %edx
movl %eax, %ecx
movl %edx, %ebx
movl %esi, %eax
movl %eax, -48(%ebp)
movl $0, -44(%ebp)
movl -48(%ebp), %eax
andb $255, %ah
movl -44(%ebp), %edx
andl $15, %edx
movl %eax, -48(%ebp)
movl %edx, -44(%ebp)
movl -48(%ebp), %ecx
movl -44(%ebp), %ebx
shldl $5, %ecx, %ebx
sall $5, %ecx
movl %ecx, %eax
andb $255, %ah
movl %ebx, %edx
andl $15, %edx
movl %eax, %ecx
movl %edx, %ebx
movl %esi, %eax
sall $2, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
movl %esp, -36(%ebp)
movl -36(%ebp), %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -36(%ebp)
movl -36(%ebp), %edx
movl %edx, -24(%ebp)
movl -24(%ebp), %edx
movl 8(%ebp), %eax
movl %eax, 8(%edx)
movl -24(%ebp), %eax
movl 8(%eax), %eax
movl %edi, %esp
movl -20(%ebp), %edx
xorl %gs:20, %edx
je .L3
call __stack_chk_fail
.L3:
leal -12(%ebp), %esp
popl %ebx
popl %esi
popl %edi
popl %ebp
ret
.size f, .-f
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
movl $5, (%esp)
call f
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
movl $0, %eax
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",@progbits
Right now, I have some questions:
main. Can someone explain why?More questions will follow
Just found that this is a valid C99 extension, that the array’s content is allocated on heap and some more things :)
This works because it moves the stack pointer dynamically to accommodate the size of the array. You can’t change the size of main()’s stack.
Please fix the memory leak in your program and try again, but this time with -O2 instead of -O0.
For -DEXT I get:
0000000000400570 :
400570: 55 push %rbp
400571: b8 05 00 00 00 mov $0×5,%eax
400576: 48 89 e5 mov %rsp,%rbp
400579: 48 83 ec 30 sub $0×30,%rsp
40057d: c9 leaveq
40057e: c3 retq
40057f: 90 nop
0000000000400580 :
400580: 48 83 ec 08 sub $0×8,%rsp
400584: e8 e7 ff ff ff callq 400570
400589: be 9c 06 40 00 mov $0x40069c,%esi
40058e: 89 c2 mov %eax,%edx
400590: bf 01 00 00 00 mov $0×1,%edi
400595: 31 c0 xor %eax,%eax
400597: e8 bc fe ff ff callq 400458
40059c: 31 c0 xor %eax,%eax
40059e: 48 83 c4 08 add $0×8,%rsp
4005a2: c3 retq
While for calloc using version I get:
0000000000400600 :
400600: 48 83 ec 08 sub $0×8,%rsp
400604: be 04 00 00 00 mov $0×4,%esi
400609: bf 05 00 00 00 mov $0×5,%edi
40060e: e8 ed fe ff ff callq 400500
400613: 48 89 c7 mov %rax,%rdi
400616: c7 40 08 05 00 00 00 movl $0×5,0×8(%rax)
40061d: e8 ce fe ff ff callq 4004f0
400622: ba 05 00 00 00 mov $0×5,%edx
400627: be 2c 07 40 00 mov $0x40072c,%esi
40062c: bf 01 00 00 00 mov $0×1,%edi
400631: 31 c0 xor %eax,%eax
400633: e8 98 fe ff ff callq 4004d0
400638: 31 c0 xor %eax,%eax
40063a: 48 83 c4 08 add $0×8,%rsp
40063e: c3 retq
@Author:
I observed that this declaration doesn’t work in main. Can someone explain why?
You messed up your code. http://codepad.org/QtjzqWf8 works for me.
Is this a gcc extension or it is in the standards (too lazy now to boot up my Windows VM and test with cl)
It’s not little known, nor is it specific to gcc. See http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
@Mithrandir: Read the gnu.org link. The array is declared on the stack, not the heap. I wouldn’t call it a C99 extension, as it is defined in the C99 standard.
@Anthony: All functions share the same stack… I have no idea what you’re talking about. See codepad link above.
Yeah, I got a series of mistakes in writing the comments and the article :(
[...] This post was mentioned on Twitter by guillaume sempe, siyo's sbm. siyo's sbm said: GCC: GCC Array | Code and Bugs : http://pgraycode.wordpress.com/2010/05/01/gcc-array/ [...]