Reputation: 2227
I don't know if my title is appropriate, cause my problem is: I know sometimes (f.e when I want to make use of argv[]) compiler has to arrange space on the stack for the command line arguments. Now I wrote a simple program just to see how the C compiler handles simple C arrays (actually it handles them the same way as std::array
's). I'm using Manjaro Linux 64 bit. C code looks like this:
#include <stdio.h>
int main(){
int a[5] = {1,2,3,4,5};
//printf("%d", a[1]);
return 0;
}
The assembly generated output (from gcc main.c -fno-asynchronous-unwind-tables -o XD.s -S
):
.file "main.c"
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
movl $1, -32(%rbp)
movl $2, -28(%rbp)
movl $3, -24(%rbp)
movl $4, -20(%rbp)
movl $5, -16(%rbp)
movl $0, %eax
popq %rbp
ret
.size main, .-main
.ident "GCC: (GNU) 6.3.1 20170109"
.section .note.GNU-stack,"",@progbits
Now, when I uncomment printf
statement, the code looks like this:
.file "main.c"
.section .rodata
.LC0:
.string "%d"
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
movl $1, -32(%rbp)
movl $2, -28(%rbp)
movl $3, -24(%rbp)
movl $4, -20(%rbp)
movl $5, -16(%rbp)
movl -28(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (GNU) 6.3.1 20170109"
.section .note.GNU-stack,"",@progbits
The middle part is obvious, just calling printf
. But why did compiler put a subq $32, %rsp
line here? Why doesn't it appear in the first example, without printf
statement?
Upvotes: 1
Views: 1084
Reputation: 9203
This is an optimization your compiler does. It realizes in the first case that main is a leaf function and hence it knows that the array would be safe on the stack. Whereas in the second case, the call to printf would overwrite the stack frame and hence it protects it by incrementing the %rsp.
Actually there are many such optimizations compilers do. For instance the ABI specifies that the stack must be 16 bytes aligned before call and the frame created in such a way that the %rsp is 16 bytes aligned. But in case the function doesn't call any other function or doesn't use any SSE instructions (one example of instruction which requires aligned stack frame) it breaks the ABI requirements. These are really just micro optimizations done to save every byte possible.
Upvotes: 5
Reputation: 16596
I added comments to each line of assembly.
main:
pushq %rbp ; save old stack frame
movq %rsp, %rbp ; rbp = stack frame of this function
subq $32, %rsp ; 32 bytes reserved on stack for local variable(s)
movl $1, -32(%rbp) ; a[0] = 1 (at rbp-32 == rsp)
movl $2, -28(%rbp) ; a[1] = 2
movl $3, -24(%rbp) ; a[2] = 3
movl $4, -20(%rbp) ; a[3] = 4
movl $5, -16(%rbp) ; a[4] = 5 (rbp-16 == rsp+16)
; remaining 12B from rbp-12 to rbp-1 is not used ("wasted")
; but it works as "padding" to have correctly aligned rsp for printf
movl -28(%rbp), %eax ; eax = a[1]
movl %eax, %esi ; esi = a[1] (argument for printf)
movl $.LC0, %edi ; edi = format string pointer
movl $0, %eax ; eax = 0 (zero FP/SSE arguments)
call printf
movl $0, %eax ; return value of main
leave ; restore stack frame and exit main
ret
Upvotes: 4
Reputation: 1
You should compile your (real) code with gcc -S -fverbose-asm -O
if you want to look into the generated .s
assembler file.
Notice that recent ABI and calling conventions require the stack pointer to be 16 byte aligned at least (in particular, for compatibility with AVX or SSE). Read also about the Red Zone (as suggested by Zang Ming Jie).
But why did compiler put a
subq $32, %rsp
line here? Why doesn't it appear in the first example, withoutprintf
statement?
Probably because without any calls to printf
your main
has become a leaf routine.
So the compiler don't need to update %rsp
to be ABI compliant (in the called printf
call frame).
Upvotes: 4
Reputation: 5275
rsp is used to pass frame point to inner calls, if a function doesn't call other function, it don't need to adjust rsp offset.
NOTE: There is a 128-byte area beyond the location pointed to by %rsp called red zone. Even if the function doesn't adjust rsp, its red zone is still protected.
Upvotes: 2