【发布时间】:2018-02-20 23:49:36
【问题描述】:
当我尝试编译以下程序时
#include <iostream>
#include <memory>
#include <thread>
#include <vector>
// This function will be called from a thread
void call_from_thread()
{
std::cout << "Threaded: Hello, World" << std::endl;
}
int main()
{
std::cout << "Hello World" << std::endl;
std::thread t1(call_from_thread);
t1.join();
std::cout << "Goodbye World" << std::endl;
}
通过这个电话
pi@raspberrypi:/tmp $ arm-linux-gnueabihf-g++ -g -Wall -O0 -ggdb -Wl,-z,nocopyreloc segfault_check.cpp -o segv_test -lpthread
它将在没有警告的情况下编译。在这种情况下,目标机器是运行 rapbian stretch 和 gcc 6.3.0 的 raspberry 计算模块 3。尝试运行它会在到达主入口点之前立即导致段错误。
GNU gdb (Raspbian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from segv_test...done.
(gdb) run
Starting program: /tmp/segv_test
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
(gdb) bt
#0 0x00000000 in ?? ()
#1 0x76e99148 in __dynamic_cast () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#2 0x76f105f4 in bool std::has_facet<std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > > >(std::locale const&) () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#3 0x76f02f94 in std::basic_ios<char, std::char_traits<char> >::_M_cache_locale(std::locale const&) () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#4 0x76f030c0 in std::basic_ios<char, std::char_traits<char> >::init(std::basic_streambuf<char, std::char_traits<char> >*) () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#5 0x76eab684 in std::ios_base::Init::Init() () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#6 0x00010de8 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at /usr/include/c++/6/iostream:74
#7 0x00010e28 in _GLOBAL__sub_I__Z16call_from_threadv () at segfault_check.cpp:44
#8 0x00011db4 in __libc_csu_init ()
#9 0x76c5460c in __libc_start_main (main=0x7efff214, argc=1993838592, argv=0x76c5460c <__libc_start_main+168>, init=0x11d68 <__libc_csu_init>, fini=0x11dc8 <__libc_csu_fini>, rtld_fini=0x76fdf9b8 <_dl_fini>, stack_end=0x7efff214)
at libc-start.c:247
#10 0x00010a78 in _start ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)
但是,如果我放弃 nocopyreloc 指令,一切似乎都可以工作:
pi@raspberrypi:/tmp $ arm-linux-gnueabihf-g++ -g -Wall -O0 -ggdb segfault_check.cpp -o segv_test -lpthread
pi@raspberrypi:/tmp $ ./segv_test
Hello World
Threaded: Hello, World
Goodbye World
直到今天我还不知道nocopyreloc 选项。它通过我们用于交叉编译的 CMake 默认 CMAKE_EXE_LINKER_FLAGS 设置 工具链文件进入。 binutils documentation 声明:
nocopyreloc 禁用复制重定位的生产。
这没什么好解释的。
当我在我的开发机器 (linux x86_64) 上使用 g++ 7.2.0 编译程序时,我收到以下错误消息
./segv_test: Symbol `_ZSt4cout' causes overflow in R_X86_64_PC32 relocation
./segv_test: Symbol `_ZSt4cout' causes overflow in R_X86_64_PC32 relocation
./segv_test: Symbol `_ZSt4cout' causes overflow in R_X86_64_PC32 relocation
./segv_test: Symbol `_ZTVNSt6thread6_StateE' causes overflow in R_X86_64_PC32 relocation
Segmentation fault (core dumped)
这似乎暗示了问题的原因。显然加载器无法执行必要的重定位,但我不太了解该过程的细节。
我想知道我是否可以安全地放弃nocopyreloc 选项,或者我是否需要以不同的方式构建我的库或两者兼而有之?还是什么?
【问题讨论】: