这是记录在案的 gdb 和 is (supposed to be) configurable 的行为。
当我使用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 ()
(在这种情况下,我知道有三个 main() 帧,而不仅仅是一个。)
因此我得出结论,这与gdb 本身有关。
经过进一步调查,发现这种行为是documented:
大多数程序都有一个标准的用户入口点——系统库和启动代码转换为用户代码的地方。对于 C,这是main。当gdb 在回溯中找到入口函数时,它将终止回溯,以避免追踪到高度系统特定(通常是无趣)的代码。
当我在gdb 中设置以下内容时:
set backtrace past-main on
set backtrace past-entry on
它开始显示两个main() 帧。由于某种原因,它仍然没有深入。