user7295860
user7295860

Reputation:

GCC generated assembly

Why printf function causes the change of prologue?

C code_1:

#include <cstdio>

int main(){
  int a = 11;
  printf("%d", a);
}

GCC -m32 generated one:

.LC0:
        .string "%d"
main:
        lea     ecx, [esp+4]           // What's purpose of this three
        and     esp, -16               // lines?
        push    DWORD PTR [ecx-4]      // 
        push    ebp
        mov     ebp, esp
        push    ecx
        sub     esp, 20                // why sub 20?
        mov     DWORD PTR [ebp-12], 11
        sub     esp, 8
        push    DWORD PTR [ebp-12]
        push    OFFSET FLAT:.LC0
        call    printf
        add     esp, 16
        mov     eax, 0
        mov     ecx, DWORD PTR [ebp-4]
        leave
        lea     esp, [ecx-4]
        ret

C code_2:

#include <cstdio>

int main(){
  int a = 11;
}

GCC -m32:

main:
        push    ebp
        mov     ebp, esp
        sub     esp, 16
        mov     DWORD PTR [ebp-4], 11
        mov     eax, 0
        leave
        ret

What is the purpose of first three lines added in first code? Please, explain first assembly code, if you can.

EDIT:

64-bit mode:

.LC0:
        .string "%d"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 11
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        mov     eax, 0
        leave
        ret

Upvotes: 7

Views: 1039

Answers (1)

Margaret Bloom
Margaret Bloom

Reputation: 44136

The insight is that the compiler keep the stack aligned at function calls.
The alignment is 16 byte.

lea     ecx, [esp+4]           ;Save original ESP to ECX (ESP+4 actually)
and     esp, -16               ;Align stack on 16 bytes (Lower esp)

push    DWORD PTR [ecx-4]      ;Push main return address (Stack at 16B + 4)
                               ;My guess is to aid debugging tools that expect the RA
                               ;to be at [ebp+04h]
push    ebp
mov     ebp, esp               ;Prolog (Stack at 16B+8)

push    ecx                    ;Save ECX (Original stack pointer) (Stack at 16B+12)

sub     esp, 20                ;Reserve 20 bytes (Stack at 16B+0, ALIGNED AGAIN)
                               ;4 for alignment + 1x16 for a variable (variable space is
                               ;allocated in multiple of 16)

mov     DWORD PTR [ebp-12], 11 ;a = 11

sub     esp, 8                 ;Stack at 16B+8 for later alignment
push    DWORD PTR [ebp-12]     ;a
push    OFFSET FLAT:.LC0       ;"%d"     (Stack at 16B)
call    printf
add     esp, 16                ;Remove args+pad from the stack (Stack at 16B)

mov     eax, 0                 ;Return 0

mov     ecx, DWORD PTR [ebp-4] ;Restore ECX without the need to add to esp
leave                          ;Restore EBP

lea     esp, [ecx-4]           ;Restore original ESP
ret

I don't know why the compiler saves esp+4 in ecx instead of esp (esp+4 is the address of the first parameter of main).

Upvotes: 8

Related Questions