21. 编译选项static导致程序Sgmentation fault

可以轻易使用tar2node复现:

git clone https://github.com/LyleLee/tars2node.git
git checkout static_segmentation_fault
cd tars2node/build
cmake ..
make
[user@centos build]$ ./tars2node
Segmentation fault (core dumped)

21.1. 定位过程

查阅资料发现pthread静态链接时会有问题,原因是pthread.a没有整个包含到目标程序当中。网上提示使用-Wl,–whole-archive。 但是仍然会有错误

 # flag
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-sign-compare -Wno-unused-result -static")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -static")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-sign-compare -Wno-unused-result -static -Wl,--whole-archive")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -static -Wl,--whole-archive")

添加

-Wl,--whole-archive

可以看到具体错误:

/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/libc.a(s_signbitl.o): In function `__signbitl':
(.text+0x0): multiple definition of `__signbitl'
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/libm.a(m_signbitl.o):(.text+0x0): first defined here
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/libc.a(mp_clz_tab.o):(.rodata+0x0): multiple definition of `__clz_tab'
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/libgcc.a(_clz.o):(.rodata+0x0): first defined here
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/libc.a(rcmd.o): In function `__validuser2_sa':
(.text+0x54c): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/libc.a(dl-conflict.o): In function `_dl_resolve_conflicts':
(.text+0x28): undefined reference to `_dl_num_cache_relocations'
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/libc.a(dl-conflict.o): In function `_dl_resolve_conflicts':
(.text+0x34): undefined reference to `_dl_num_cache_relocations'
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/libc.a(dl-conflict.o): In function `_dl_resolve_conflicts':
(.text+0x48): undefined reference to `_dl_num_cache_relocations'
collect2: error: ld returned 1 exit status
make[2]: *** [tars2node] Error 1
make[1]: *** [CMakeFiles/tars2node.dir/all] Error 2
make: *** [all] Error 2
[me@centos build]$
[me@centos build]$

上面的报错,提示libm和libc中有重复定义的函数, 这个是让人很疑惑的,上网搜索,没有相关资料描述。 同时查询了_dl_num_cache_relocations,仍然没有线索,后来怀疑弱符号等原因,查阅了很多资料。 没有什么思路。

换个思维方式,只是想静态链接程序,什么错误先不管,如何才能正确地静态链接呢。最终找到了要想静态链接,不同编译器地选项是不一样的。

解决问题:

[100%] Linking CXX executable tars2node
/usr/bin/ld: cannot find -lgcc_s
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
make[2]: *** [tars2node] Error 1
make[1]: *** [CMakeFiles/tars2node.dir/all] Error 2
make: *** [all] Error 2

使用-static-libgcc -static-libstdc++编译选项可以消除这个报错

21.2. 解决办法:

21.2.1. 一、使用动态链接库,去掉-static选项

编辑../CMakeList.txt取消-static

 # flag
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-sign-compare -Wno-unused-result -static")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -static")

21.2.2. 二、使用gcc/g++ 8.0及以上

升级办法参考【devtoolset】

21.2.3. 三、使用低版本gcc如4.8.5

yum install glibc-static

使用-Wl,-Bdynamic编译选项

# flag
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-sign-compare -Wno-unused-result -static")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -static")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-sign-compare -Wno-unused-result -Wl,-Bdynamic")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -Wl,-Bdynamic")