1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

clang で最適化レベル 0 でコンパイルすると main() 中に出現する謎のオブジェクト

Last updated at Posted at 2018-07-02

なんだこれ? 誰か教えて。

$ 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
$ 

何か分かったら追記します。

1
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?