Reputation: 3786
_main:
; create stack frame
pushl %ebp
movl %esp, %ebp
; save one local variable
subl $8, %esp
; zero four rightmost bits of esp
andl $-16, %esp
; set eax to (0 + 15 + 15) / 2^4 * 2^4 = 16
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
; set local variable to eax (16)
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
; call allocation and main
call __alloca
call ___main
; set eax to zero (return value)
movl $0, %eax
; fold stack frame and return to caller
leave
ret
I compiled a int main(){return 0;}
C code using gcc -S return_zero.c
(on Windows) and this is what I got (I removed the assembler directives and added explanation comment as much as I understood. Correct me if I'm wrong, please.).
I don't understand three things:
I got somewhat unclear explanations to both #1 and #3 on the internet so I'd like if someone can answer more deeply and for #2 I haven't find any explanation so if someone can explain it'll be great.
If any further information is needed comment and I'll post it.
Thanks!
Upvotes: 2
Views: 237
Reputation: 23236
The Intel Core i5 uses a 64 bit architecture.
Addressing questions 1, and partially 2, From an Overview of x64 Calling Conventions:
Alignment
Most structures are aligned to their natural alignment. The primary exceptions are the stack pointer and malloc or alloca memory, which are aligned to 16 bytes in order to aid performance. Alignment above 16 bytes must be done manually, but since 16 bytes is a common alignment size for XMM operations, this should work for most code. For more information about structure layout and alignment see Types and Storage. For information about the stack layout, see Stack Usage.
regarding the part of your question: ...why it is done in such a complicated way. Only a guess, but from the quote, the complexity may be due in part to accommodate portability.
Borrowing from this post, (also having tags gcc
, compiler-construction
& assembly
) is a very good line by line explanation of some of the same code you are trying to interpret. An excerpt:
In step 1 we save the pointer to the old stack frame on the stack by calling, pushl %ebp. Since main is the first function called, I have no idea what the previous value of %ebp points too.
Step 2, We are entering a new stack frame because we are entering a new function (main). Therefore, we must set a new stack frame base pointer. We use the value in esp to be the beginning of our stack frame.
Step 3. Allocates 8 bytes of space on the stack. As we mentioned above, the stack grows toward lower addresses thus, subtracting by 8, moves the top of the stack by 8 bytes.
...
and regarding calling __alloca & __main
...
Steps 12 and 13 setup the c library.
Upvotes: 1