なんだこれ? 誰か教えて。
$ cat -n test.c
1 int main(void)
2 {
3 return 0;
4 }
$ clang-5.0 -O0 -fomit-frame-pointer test.c -S -o -
.text
.file "test.c"
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.cfi_startproc
# BB#0:
xorl %eax, %eax
movl $0, -4(%rsp) ←これです
retq
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
# -- End function
.ident "clang version 5.0.0-3 (tags/RELEASE_500/final)"
.section ".note.GNU-stack","",@progbits
$
初期化するだけで参照はされないみたいで、最適化レベルを上げると不要なオブジェクトとして削除されるようなので実害はないみたいなんですけどね、なんか気持ち悪いですね。
$ clang-5.0 -O1 -fomit-frame-pointer test.c -S -o -
.text
.file "test.c"
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.cfi_startproc
# BB#0:
xorl %eax, %eax
retq
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
# -- End function
.ident "clang version 5.0.0-3 (tags/RELEASE_500/final)"
.section ".note.GNU-stack","",@progbits
$
`-emit-llvm' を指定して LLVM IR を吐かせても謎のオブジェクトの確保と初期化は確認できます。
$ clang-5.0 -O0 test.c -S -emit-llvm -o -
; ModuleID = 'test.c'
source_filename = "test.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
; Function Attrs: noinline nounwind optnone uwtable
define i32 @main() #0 {
%1 = alloca i32, align 4 ←確保
store i32 0, i32* %1, align 4 ←初期化
ret i32 0
}
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 5.0.0-3 (tags/RELEASE_500/final)"}
$
main() 以外の通常の関数ではこのようなオブジェクトは生成されず、通常の関数の中で未使用の変数を初期化だけした場合のコードが今回の main() のそれと同じようになるようです。
$ cat -n test2.c
1 int main(void)
2 {
3 return 0;
4 }
5
6 int hoge(void)
7 {
8 return 0;
9 }
10
11 int piyo(void)
12 {
13 int a = 0;
14 return 0;
15 }
$ clang-5.0 -O0 -fomit-frame-pointer test2.c -S -o -
.text
.file "test2.c"
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.cfi_startproc
# BB#0:
xorl %eax, %eax
movl $0, -4(%rsp) ←これと
retq
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
# -- End function
.globl hoge # -- Begin function hoge
.p2align 4, 0x90
.type hoge,@function
hoge: # @hoge
.cfi_startproc
# BB#0:
xorl %eax, %eax
retq
.Lfunc_end1:
.size hoge, .Lfunc_end1-hoge
.cfi_endproc
# -- End function
.globl piyo # -- Begin function piyo
.p2align 4, 0x90
.type piyo,@function
piyo: # @piyo
.cfi_startproc
# BB#0:
xorl %eax, %eax
movl $0, -4(%rsp) ←これ
retq
.Lfunc_end2:
.size piyo, .Lfunc_end2-piyo
.cfi_endproc
# -- End function
.ident "clang version 5.0.0-3 (tags/RELEASE_500/final)"
.section ".note.GNU-stack","",@progbits
$
main() から return を省略して暗黙的に 0 を返すようすると先のオブジェクトは出現しなくなるようです。main() と通常の関数との違う部分ですがこの辺りに原因があるかもですね。
$ cat -n test3.c
1 int main(void)
2 {
3 }
$ clang-5.0 -O0 -fomit-frame-pointer test3.c -S -o -
.text
.file "test3.c"
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.cfi_startproc
# BB#0:
xorl %eax, %eax
retq
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
# -- End function
.ident "clang version 5.0.0-3 (tags/RELEASE_500/final)"
.section ".note.GNU-stack","",@progbits
$
何か分かったら追記します。