今天我对此感到惊讶:
\n#include <stdlib.h> // for the 'exit' call\n\nint foo() {\n // return 0;\n}\n\nint main() {\n int res = foo();\n exit(res);\n}\nRun Code Online (Sandbox Code Playgroud)\n我知道忘记返回 ; 中的预期整数值不是好形式foo。但你会期望这段代码出现段错误吗?
以下是 GCC7.5 中发生的情况:
\n(thanassis)$ g++ -O3 -Wall a.cc\na.cc: In function \xe2\x80\x98int foo()\xe2\x80\x99:\na.cc:5:5: warning: no return statement in function returning non-void [-Wreturn-type]\n }\n ^\n\n(thanassis)$ ./a.out \n\n(thanassis)$ gdb ./a.out\nGNU gdb (Ubuntu 10.2-0ubuntu1~18.04~2) 10.2\nCopyright (C) 2021 Free Software Foundation, Inc.\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\nType "show copying" and "show warranty" for details.\nThis GDB was configured as "x86_64-linux-gnu".\nType "show configuration" for configuration details.\nFor bug reporting instructions, please see:\n<https://www.gnu.org/software/gdb/bugs/>.\nFind the GDB manual and other documentation resources online at:\n <http://www.gnu.org/software/gdb/documentation/>.\n\nFor help, type "help".\nType "apropos word" to search for commands related to "word"...\nReading symbols from ./a.out...\n(No debugging symbols found in ./a.out)\n\n(gdb) run\nStarting program: /home/thanassis/a.out \n[Inferior 1 (process 24749) exited normally]\n\n(gdb) quit\nRun Code Online (Sandbox Code Playgroud)\n没问题。都好。
\n是的,忽略设置返回值的事实foo意味着 ABI (EAX) 为任务选择的寄存器将有垃圾。任何。
现在看看 GCC11 会发生什么:
\n(thanassis)$ g++ -O3 -Wall ./a.cc \n./a.cc: In function \xe2\x80\x98int foo()\xe2\x80\x99:\n./a.cc:5:5: warning: no return statement in function returning non-void [-Wreturn-type]\n 5 | }\n | ^\n\n(thanassis)$ ./a.out \nSegmentation fault (core dumped)\n\n(thanassis)$ gdb ./a.out\nGNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2\nCopyright (C) 2020 Free Software Foundation, Inc.\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\nType "show copying" and "show warranty" for details.\nThis GDB was configured as "x86_64-linux-gnu".\nType "show configuration" for configuration details.\nFor bug reporting instructions, please see:\n<http://www.gnu.org/software/gdb/bugs/>.\nFind the GDB manual and other documentation resources online at:\n <http://www.gnu.org/software/gdb/documentation/>.\n\nFor help, type "help".\nType "apropos word" to search for commands related to "word"...\nReading symbols from ./a.out...\n(No debugging symbols found in ./a.out)\n(gdb) run\nStarting program: /home/thanassis/a.out \n\nProgram received signal SIGSEGV, Segmentation fault.\n0x00007ffff7ddbfaa in __libc_start_main (main=0x555555555044 <main>, argc=-136462205, argv=0x7fffff7ff0b0, init=0x555555555140 <__libc_csu_init>, \n fini=0x5555555551b0 <__libc_csu_fini>, rtld_fini=0x7fffffffe0e8, stack_end=0x7fffff7ff0a8) at ../csu/libc-start.c:141\n141 ../csu/libc-start.c: No such file or directory.\n(gdb) bt\n#0 0x00007ffff7ddbfaa in __libc_start_main (main=0x555555555044 <main>, argc=-136462205, argv=0x7fffff7ff0b0, init=0x555555555140 <__libc_csu_init>, \n fini=0x5555555551b0 <__libc_csu_fini>, rtld_fini=0x7fffffffe0e8, stack_end=0x7fffff7ff0a8) at ../csu/libc-start.c:141\n#1 0x000055555555507e in _start ()\n(gdb) \nRun Code Online (Sandbox Code Playgroud)\n现在这个情况,是我没想到的。
\n其一,堆栈帧似乎一团糟——main堆栈帧在哪里?
查看 objdump 的输出main...
$ objdump -d -S ./a.out \n...\nDisassembly of section .text:\n\n0000000000001040 <_Z3foov>:\n#include <stdlib.h>\n\n int foo() {\n 1040: f3 0f 1e fa endbr64 \n\n0000000000001044 <main>:\n // return 0;\n }\n\n int main() {\n 1044: f3 0f 1e fa endbr64 \n 1048: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)\n 104f: 00 \n\n0000000000001050 <_start>:\n 1050: f3 0f 1e fa endbr64 \n 1054: 31 ed xor %ebp,%ebp\n 1056: 49 89 d1 mov %rdx,%r9\n 1059: 5e pop %rsi\n 105a: 48 89 e2 mov %rsp,%rdx\n 105d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp\nRun Code Online (Sandbox Code Playgroud)\n...看起来 GCC 决定“合并”堆栈帧?!
\n对我来说这看起来像是一个编译器错误。请注意,忽略较旧的编译器,它也不会显示优化级别-O0--O1但它会在-O2.
再次强调一下:我知道这是不好的形式,而且我确实使用了-Walland -Wextra- 所以我确实在代码中修复了这个问题。但我想我应该在这里分享这一点,因为我从来没有预料到一个返回 int 的函数不会返回 int 来创建段错误(由于编译器创建的代码错过了堆栈帧)。
更新:另请注意,使用gcc和 not进行编译g++会创建正常的代码。该问题仅在使用 C++ 编译器编译代码时才会出现。
| 归档时间: |
|
| 查看次数: |
160 次 |
| 最近记录: |