2016-12-10 21 views
1

Iは、次のCコードのために最適化されていないコードを生成した:GCCで自動変数はどのように初期化されますか?それらは0であることが保証されていますか?

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

と生成されたコードは次のとおり

.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 

は、上記アセンブリコードの実行は出力として0を与えます。 私の質問は、変数iはどのように0に初期化されていますか?

+0

「i」は配列ではありません。それは特定の値に初期化されていません。 –

+2

未定義です。 – MrTux

+3

[静的でない変数の初期化]の可能な複製(http://stackoverflow.com/questions/8743445/non-static-variable-initialization) – MrTux

答えて

2

は私が0

に変数初期化取得する方法はありません。あなたのCコードはundefined behaviourであり、アセンブリにはそのことが反映されています。

Herehereは、Linux上のプロセスの起動状態のいくつかの古い情報である。それは多少関連しているが、未定義の動作に関する主なポイントは無効になりません。)

+1

@MadhavDatt完全に定義されていません。プログラムは '0'、' '1、' '3446710249680232'、' 'giraffe''または' segmentation fault:core dumped'を出力できます。 –

+1

'i'の値は不定であり、トラップ表現である可能性があります。不定値を使用しようとすると、未定義の動作につながります。 –

+1

@ JohnBode:x86には整数のトラップ表現がないことに注意してください。その点は一般的にCに当てはまりますが、OPの特定のケースで 'i'がどのように初期化されるのかについてではありません。 (私の答えを見てください。) –

3

NPE's answerあなたはすべてC告げます標準はこのプログラムについて言わなければならない:その振る舞いは(完全に)未定義である。

Linux上でgcc -O0の最適化されていないasmからゼロが得られる理由を説明するために、コンパイラが生成したので説明します。

haroldが指摘するように、書き込みを行わなかったことをスタックメモリから読み出します。 Linuxカーネルは、情報漏えいを防ぐために、スタックのページをゼロにします。 (同じと同じ)printfへの呼び出しの直前に、起動コードのどれもがmainというスタックスペースを使用していないので、このロードによって、その初期ゼロ状態が検出されます。

もちろん、printfが返された後、RSPの下のスタックはダーティになります。動的リンクは「遅れて」行われるため、call printfの直後に発生します(リンクされたオブジェクトファイルをobjdump -drwC -Mintel a.outで逆アセンブルすると、実際にはcall [email protected]になります)。おそらく、一時的な格納のためにいくつかのスタックスペースを使用しています。 (動的にリンクされたバイナリでライブラリ関数の最初の呼び出しにステップインした場合、実際のライブラリ関数コードに達する前に〜100万命令が表示されます[私はその数値をどのように測定したか忘れてしまいますおそらく約1M命令であると私に言ったことを思い出してください。] printfは確かにいくつかのレジスタをプッシュ/ポップし、スタック上の他のスクラッチスペースを使用します。

関連する問題