每https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
注意,某些编译器优化可能会干扰获得有效的回溯。函数内联导致内联函数没有堆栈帧;尾调用优化将一个堆栈帧替换为另一个堆栈帧;帧指针消除将阻止反向跟踪正确解释堆栈内容。
我想知道为什么在启用尾优化时应该发生这种情况,以及如何避免它。
发布于 2021-02-26 06:06:23
我想知道在启用尾部优化时为什么会发生这种情况
这将发生在尾调用优化中,因为在编译器使用它之后,递归函数将不是递归函数,或者调用堆栈中将完全缺少尾递归函数。
示例:
// t.c
int foo() { return 42; }
int bar() { return foo(); }
int main() { return bar(); }
gcc -O2 -fno-inline t.c && gdb -q ./a.out
(gdb) b foo
Breakpoint 1 at 0x1140
(gdb) run
Starting program: /tmp/a.out
Breakpoint 1, 0x0000555555555140 in foo ()
(gdb) bt
#0 0x0000555555555140 in foo ()
#1 0x00007ffff7dfad0a in __libc_start_main (main=0x555555555040 <main>, argc=1, argv=0x7fffffffdc08, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdbf8) at ../csu/libc-start.c:308
#2 0x000055555555507a in _start ()main()和bar()去了哪里?我们知道main()肯定还在堆栈上。
它们是经过优化的尾部呼叫:
(gdb) disas main
Dump of assembler code for function main:
0x0000555555555040 <+0>: xor %eax,%eax
0x0000555555555042 <+2>: jmpq 0x555555555150 <bar>
End of assembler dump.
(gdb) disas bar
Dump of assembler code for function bar:
0x0000555555555150 <+0>: xor %eax,%eax
0x0000555555555152 <+2>: jmp 0x555555555140 <foo>
End of assembler dump.如何避免它。
避免这种情况的唯一方法是禁用尾调用优化(使用-fno-optimize-sibling-calls):
gcc -O2 -fno-inline t.c -fno-optimize-sibling-calls && gdb -q ./a.out
(gdb) b foo
Breakpoint 1 at 0x1140
(gdb) run
Starting program: /tmp/a.out
Breakpoint 1, 0x0000555555555140 in foo ()
(gdb) bt
#0 0x0000555555555140 in foo ()
#1 0x0000555555555157 in bar ()
#2 0x0000555555555047 in main ()https://stackoverflow.com/questions/66379780
复制相似问题