2
_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:

  • Why does the compiler align esp to 16?
  • Why is eax set to 16, why it is done in such a complicated way, and why is there a local variable also set to 16?
  • What are __alloca and ___main?

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!

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
Neo
  • 3,534
  • 2
  • 20
  • 32
  • 3
    Try compiling with optimizations. – Kerrek SB May 10 '17 at 18:06
  • @KerrekSB I compiled with -O3. It removed the whole eax = 16 thing and uses xorl instead of movl to set eax to 0 at the end but it still does all the other stuff (including declaring a local variable). Also I'm curious why it does this anyway. – Neo May 10 '17 at 18:11
  • What platform is this for? I can't reproduce this on Linux. – Kerrek SB May 10 '17 at 18:14
  • @KerrekSB I'm using Windows 8.1 with Intel Core i5. – Neo May 10 '17 at 18:16
  • Checkout the Windows ABI, specifically register spilling and red zones. – Kerrek SB May 10 '17 at 18:28
  • @KerrekSB Thanks. So it's connected to the `call __alloca`? I still don't get why would it have the value of 16. – Neo May 10 '17 at 19:08
  • The call to `__alloca` allocates space on the stack. It's necessary when the amount being allocate on the stack could be over 4092 bytes. It's not necessary here. The call `___main` is for initialization that needs to be done before the start of the program. It shouldn't be necessary, as this initialization should have been done be `_main` was called. These are probably artifacts of the MinGW port of GCC which has issues like these. – Ross Ridge May 10 '17 at 19:47
  • @RossRidge OK, thanks! – Neo May 11 '17 at 07:16
  • My guess here is that you would get more information if your main function had arguments. I suspect that what you are seeing comes from a main template that will do processing for arguments. – user3344003 May 11 '17 at 19:43

1 Answers1

1

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.

Community
  • 1
  • 1
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • OK, so the aligning is some kind of Windows convention? But I still don't get the eax and local variable part. Are they some kind of argument to __alloca? This doesn't make sense. – Neo May 10 '17 at 18:51
  • But it doesn't hold the former value of `esp`, it holds the value of 16, doesn't it? – Neo May 10 '17 at 19:02
  • Neo - _subl $8, %esp_ Here, the compiler appears to be reserving space on the stack. I am not sure why it reserves 8. Again, likely directly related to alignment. It probably will contain left most bits of esp after clearing the rightmost bits. – ryyker May 10 '17 at 19:07
  • So it's some kind of argument for `__alloca`? – Neo May 10 '17 at 19:09
  • @Neo - `andl $-16, %esp` aligns esp to a 16 byte boundary. ( from references _[here](http://stackoverflow.com/questions/23309863/why-does-gcc-produce-andl-16)_ and _[here](http://stackoverflow.com/questions/2465232/what-does-subl-do-here)_ ) – ryyker May 10 '17 at 19:17
  • @Neo - the link (and an excerpt) edited into my answer above details some answers to similar questions you are asking. Hope it helps. ( I am very new to assembly. ) – ryyker May 10 '17 at 19:30