これは の文書化された動作でありgdb
、(想定されている) 構成可能です。
gcc 4.7.2
( )を使用してコードをコンパイルすると-O3
、次のアセンブリが得られます。
_main:
LFB1:
movl _i.2134(%rip), %eax
cmpl $10, %eax
jle L6
xorl %eax, %eax
ret
L6:
addl $1, %eax
pushq %rdx
LCFI0:
movl %eax, _i.2134(%rip)
xorl %eax, %eax
call _main ; <=== recursive call
popq %rcx
LCFI1:
movl $101, %esi
xorl %eax, %eax
leaq LC0(%rip), %rdi
jmp _printf
LFE1:
これは、再帰呼び出しが最適化されているという仮説に反論します。
ここで、バイナリを にロードしgdb
てブレークポイントを設定するとmain()
、繰り返しヒットします。レジスタを調べる%rsp
と、呼び出しごとにデクリメントされているため、それぞれに関連付けられたスタック フレームが明確に存在しますmain()
。
それにもかかわらず、bt
単一のフレームのみを表示します。
(gdb) bt
#0 0x0000000100000f50 in main ()
(この場合、1main()
つだけではなく 3 つのフレームがあることがわかっています。)
したがって、これはそれ自体に何らかの関係があると結論付けていgdb
ます。
さらに調査すると、この動作が文書化されていることが判明しました。
ほとんどのプログラムには、標準のユーザー エントリ ポイントがあります。これは、システム ライブラリとスタートアップ コードがユーザー コードに移行する場所です。C の場合、これはmain
. は、バックトレースでエントリ関数をgdb
見つけると、バックトレースを終了し、高度にシステム固有の (そして一般的には興味のない) コードへのトレースを回避します。
で次を設定するとgdb
:
set backtrace past-main on
set backtrace past-entry on
main()
2 つのフレームが表示され始めます。どういうわけか、それはまだ深く進んでいません。