我们可以通过在源代码中包含多个中止调用,用非常简单的示例重现此问题。在下面的示例代码中,我们在不同条件下总共有四个中止调用,但是当我们使用优化标志(-O3)进行编译时,我们只能看到一个中止调用的调试信息。因此,在这四个中止调用中发生崩溃时,gdb 总是给出具有调试信息的调用。
#include <stdio.h>
#include <stdlib.h>
void level_aa(int a)
{
if (a == 0)
abort();
if (a == 1)
abort();
if (a == 2)
abort();
abort();
}
int main(int argc,char *argv[])
{ int D;
D = atoi(argv[1]);
printf(" Value = %d", D);
level_aa(D);
return 0;
}
使用优化标志 (-O3) 编译上述代码并使用 gdb 运行以重现该问题。
>gcc -g -O3 abort_crash.c -o abort
>gdb ./abort
(gdb)run 1
(gdb) bt
#0 0x00007ffff7ab2945 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00007ffff7ab3f21 in *__GI_abort () at abort.c:92
#2 0x0000000000400634 in level_aa (a=<optimized out>) at abort_crash.c:13
#3 main (argc=<optimized out>, argv=<optimized out>) at abort_crash.c:20
(gdb)
如果我们观察第 2 帧(#2),崩溃实际上发生在第 9 行,但 gdb 显示第 13 行。我可以理解,这是由于源代码的优化而发生的。
在这种情况下,gdb 可以正常工作吗? (不删除优化)
在此先感谢您的帮助。
在这种情况下,gdb 可以正常工作吗?
GDB is在这种情况下工作正常:它向您展示了什么actually发生了,这是...
(不删除优化)
...编译器发现多条路径通向abort
不能返回且没有副作用的函数,等等merged这些路径组合在一起,减少了生成代码的大小。只需看看最终的组装结果:
(gdb) disas level_aa
Dump of assembler code for function level_aa:
0x0000000000400620 <+0>: sub $0x8,%rsp
0x0000000000400624 <+4>: callq 0x4004b0 <abort@plt>
End of assembler dump.
你所有的if
s are 完全地优化出来了。
如果你想区分不同的情况,你must让编译器知道路径是not相等的。
放一个printf
调用,或对当前翻译单元中编译器不可见的外部函数的调用(函数本身可能调用abort
):
extern int my_abort(int); // must be in a different TU
void level_aa(int a)
{
if (a == 0)
my_abort(a + 1);
if (a == 1)
my_abort(a + 2);
if (a == 2)
my_abort(a + 3);
abort();
}
注:a+1
, a+2
需要等来防止编译器合并单独的路径。如果您只是打电话my_abort(a)
,编译器可能still将它们合并在一起,就像您写的那样:
if (a >= 0 && a <= 2) my_abort(a);
请注意,如果您使用整个程序优化,即使这种外部函数方法也可能会失败。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)