Abel Tadesse
Abel Tadesse

Reputation: 145

How are automatic variables initialized in GCC? Are they guaranteed to be 0?

I generated unoptimized code for the following c code:

#include<stdio.h>
int main(){
    int i;
    printf("%d\n", i);
}

and the generated code is:

    .file   "test.c"
    .section    .rodata
.LC0:
    .string "%d\n"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    -4(%rbp), %eax
    movl    %eax, %esi
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
    .section    .note.GNU-stack,"",@progbits

Running the above assembly code gives 0 as an output. My question is, how is the variable i getting initialized to 0?

Upvotes: 1

Views: 538

Answers (2)

Peter Cordes
Peter Cordes

Reputation: 365911

NPE's answer tells you everything the C standard has to say about this program: the behaviour is (completely) undefined.

I'll take a stab at explaining why you happen to get zero from that un-optimized asm from gcc -O0 on Linux, now that the compiler has generated it.

As harold points out, it reads from stack memory that it didn't write. The Linux kernel gives your processes zeroed pages for its stack, to avoid information leaks. (Same with mmap(MAP_ANONYMOUS))

None of the startup code uses as much stack space as main right before that call to printf, so this load from it still finds that initial zeroed state.

Of course, after printf returns, the stack below RSP will be dirty. Dynamic linking is done "lazily", so that happens right after the call printf (which is actually call printf@plt if you disassemble the linked object file with objdump -drwC -Mintel a.out). That probably uses some stack space for temporary storage. (If you ever single-step into the first call to a library function in a dynamically linked binary, you'll see ~1 million instructions before execution reaches the actual library function code. [I forget how I measured that number, but I seem to recall doing something that told me it was maybe around 1M instructions.]) printf itself will certainly push/pop some registers, and maybe use some other scratch space on the stack.

Upvotes: 3

NPE
NPE

Reputation: 500913

how is the variable i getting initialized to 0

It isn't. Your C code has undefined behaviour, and the assembly reflects that.

(Here and here is some old info on the startup state of a process on Linux. It is somewhat relevant, but doesn't invalidate the main point about undefined behaviour.)

Upvotes: 2

Related Questions