g ++ -Wl,-z,nocopyreloc重定位错误

时间:2018-02-20 23:49:36

标签: c++ linux linker

当我尝试编译以下程序时

#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的覆盆子计算模块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禁用副本重定位的生成。

并没有解释太多。

当我使用g ++ 7.2.0在我的开发机器(linux x86_64)上编译程序时,我收到以下错误消息

./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选项,或者我是否需要以不同方式或两者同时构建我的库?或者什么?

1 个答案:

答案 0 :(得分:0)

nocopyreloc是为i386 abi设计的,其中动态库中的重定位也作为重定位复制到了主要可执行文件中。当时,这是唯一的这样做。复制重定位根本没有用,在极端情况下会引起问题。标志nocopyrelocs禁止此行为。我不确定它在非i386 abis上正在做什么,但是删除此标志似乎很安全。