gdb 编译make: *** [all] 错误 2_Dev 日志 | Segmentation Fault 和 GCC 编译问题排查
摘要
筆者最近在重新整理和編譯 Nebula Graph 的第三方依賴,選出兩個(gè)比較有意思的問(wèn)題給大家分享一下。
Flex Segmentation Fault——Segmentation fault (core dumped)
在編譯 Flex 過(guò)程中,遇到了 Segmentation fault:
make[2]: Entering directory '/home/dutor/flex-2.6.4/src'./stage1flex -o stage1scan.c ./scan.lmake[2]: *** [Makefile:1696: stage1scan.c] Segmentation fault (core dumped)復(fù)制代碼使用 gdb 查看 coredump:
Core was generated by `./stage1flex -o stage1scan.c ./scan.l'.Program terminated with signal SIGSEGV, Segmentation fault.#0 flexinit (argc=4, argv=0x7ffd25bea718) at main.c:976976 action_array[0] = '0';(gdb) disasDump of assembler code for function flexinit: 0x0000556c1b1ae040 : push %r15 0x0000556c1b1ae042 : lea 0x140fd(%rip),%rax # 0x556c1b1c2146 ... 0x0000556c1b1ae20f : callq 0x556c1b1af460 #這里申請(qǐng)了buffer ...=> 0x0000556c1b1ae24f : movb $0x0,(%rax) # 這里向buffer[0]寫(xiě)入一個(gè)字節(jié),地址非法,掛掉了 ...(gdb) disas allocate_arrayDump of assembler code for function allocate_array: 0x0000556c1b1af460 : sub $0x8,%rsp 0x0000556c1b1af464 : mov %rsi,%rdx 0x0000556c1b1af467 : xor %eax,%eax 0x0000556c1b1af469 : movslq %edi,%rsi 0x0000556c1b1af46c : xor %edi,%edi 0x0000556c1b1af46e : callq 0x556c1b19a100 # 調(diào)用庫(kù)函數(shù)申請(qǐng)內(nèi)存 0x0000556c1b1af473 : test %eax,%eax # 判斷是否為 NULL 0x0000556c1b1af475 : je 0x556c1b1af47e # 跳轉(zhuǎn)至NULL錯(cuò)誤處理 0x0000556c1b1af477 : cltq # 將 eax 符號(hào)擴(kuò)展至 rax,造成截?cái)?0x0000556c1b1af479 : add $0x8,%rsp 0x0000556c1b1af47d : retq ...End of assembler dump.復(fù)制代碼可以看到,問(wèn)題出在了 allocate_array 函數(shù)。因?yàn)?reallocarray 返回指針,返回值應(yīng)該使用 64 bit 寄存器rax,但 allocate_array 調(diào)用 reallocarray 之后,檢查的卻是 32 bit 的 eax,同時(shí)使用 cltq 指令將 eax 符號(hào)擴(kuò)展 到 rax。原因只有一個(gè):allocate_array 看到的 reallocarray 的原型,與 reallocarry 的實(shí)際定義不符。翻看編譯日志,確實(shí)找到了 implicit declaration of function 'reallocarray' 相關(guān)的警告。configure 階段添加 CFLAGS=-D_GNU_SOURCE 即可解決此問(wèn)題。
注:此問(wèn)題不是必現(xiàn),但編譯/鏈接選項(xiàng) -pie 和 內(nèi)核參數(shù) kernel.randomize_va_space 有助于復(fù)現(xiàn)。
總結(jié):
- 隱式聲明的函數(shù)在 C 中,返回值被認(rèn)為是 int。
- 關(guān)注編譯器告警,-Wall -Wextra 要打開(kāi),開(kāi)發(fā)模式下最好打開(kāi) -Werror。
GCC Illegal Instruction——internal compiler error: Illegal instruction
前陣子,接到用戶反饋,在編譯 Nebula Graph 過(guò)程中遭遇了編譯器非法指令的錯(cuò)誤,詳見(jiàn)(#978)[github.com/vesoft-inc/…]
錯(cuò)誤信息大概是這樣的:
Scanning dependencies of target base_obj_gch[ 0%] Generating Base.h.gchIn file included from /opt/nebula/gcc/include/c++/8.2.0/chrono:40,from /opt/nebula/gcc/include/c++/8.2.0/thread:38,from /home/zkzy/nebula/nebula/src/common/base/Base.h:15:/opt/nebula/gcc/include/c++/8.2.0/limits:1599:7: internal compiler error: Illegal instructionmin() _GLIBCXX_USE_NOEXCEPT { return FLT_MIN; }^~~0xb48c5f crash_signal../.././gcc/toplev.c:325Please submit a full bug report,with preprocessed source if appropriate.復(fù)制代碼既然是 internal compiler error,想必是 g++ 本身使用了非法指令。為了定位具體的非法指令集及其所屬模塊,我們需要復(fù)現(xiàn)這個(gè)問(wèn)題。幸運(yùn)的是,下面的代碼片段就能觸發(fā):
#include int main() { return 0;}復(fù)制代碼非法指令一定會(huì)觸發(fā) SIGILL,又因?yàn)?g++ 只是編譯器的入口,真正干活的是 cc1plus。我們可以使用 gdb 來(lái)運(yùn)行編譯命令,抓住子進(jìn)程使用非法指令的第一現(xiàn)場(chǎng):
$ gdb --args /opt/nebula/gcc/bin/g++ test.cppgdb> set follow-fork-mode childgdb> runStarting program: /opt/nebula/gcc/bin/g++ test.cpp[New process 31172]process 31172 is executing new program: /opt/nebula/gcc/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/cc1plusThread 2.1 "cc1plus" received signal SIGILL, Illegal instruction.[Switching to process 31172]0x00000000013aa0fb in __gmpn_mul_1 ()gdb> disas...0x00000000013aa086 : mulx (%rsi),%r10,%r8...復(fù)制代碼Bingo!mulx 屬于 BMI2 指令集,報(bào)錯(cuò)機(jī)器 CPU 不支持該指令集。
仔細(xì)調(diào)查,引入該指令集的是 GCC 的依賴之一,GMP。默認(rèn)情況下,GMP 會(huì)在 configure 階段探測(cè)當(dāng)前機(jī)器的 CPU 具體類型,以期最大化利用 CPU 的擴(kuò)展指令集,提升性能,但卻犧牲了二進(jìn)制的可移植性。解決方法是,在 configure 之前,使用代碼目錄中的 configfsf.guess configfsf.sub 替換或者覆蓋默認(rèn)的 config.guess 和 config.sub
總結(jié):
- 某些依賴可能因?yàn)樾阅芑蛘吲渲玫脑?#xff0c;造成二進(jìn)制的不兼容。
- 缺省參數(shù)下,GCC 為了兼容性,不會(huì)使用較新的指令集。
- 為了平衡兼容性和性能,你需要做一些額外的工作,比如像 glibc 那樣在運(yùn)行時(shí)選擇和綁定某個(gè)具體實(shí)現(xiàn)。
最后,如果你想嘗試編譯一下 Nebula 源代碼可參考以下方式:
bash> git clone https://github.com/vesoft-inc/nebula.gitbash> cd nebula && ./build_dep.sh N復(fù)制代碼有問(wèn)題請(qǐng)?jiān)?GitHub 或者微信公眾號(hào)上留言。
附錄
- Nebula Graph:一個(gè)開(kāi)源的分布式圖數(shù)據(jù)庫(kù)
總結(jié)
以上是生活随笔為你收集整理的gdb 编译make: *** [all] 错误 2_Dev 日志 | Segmentation Fault 和 GCC 编译问题排查的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: hal库开启中断关中断_[STM32]H
- 下一篇: 连接定义点作用_最坏情况下最优连接(Wo