G -WL,-Z,Nocopyloc重定位误差

g++ -Wl,-z,nocopyreloc relocation error

本文关键字:定位 误差 -WL Nocopyloc      更新时间:2023-10-16

当我尝试编译以下程序

#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 -linux -gnueaeabihf -g -g -wall -o0 -o0 -ggdb -wl,-z,-z,nocopylelec segfault_check.cpp-cpp -ogv_test -o segv_test -segv_test -lpthRad>

它将在没有警告的情况下进行编译。在这种情况下,目标机是Raspberry Compute模块3运行Rapbian Stretch和GCC 6.3.0。试图运行它将导致立即发生的segfault,甚至在达到主入口点之前。

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 -linux -gnueabihf -g -g -wall -o0 -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文档指出:

nocopyloc禁用副本重新定位的生产。

没有太多解释。

当我用G 7.2.0在Dev Machine(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选项,还是我需要以不同的或两者的方式构建我的Libs?或什么?

nocopyloc是为i386 ABI设计的,其中从动态库中的recrocs也被复制为主要可执行文件中的relocs。当时,这是唯一这样做的ABI。标志Nocopylocs抑制了这种行为。我不确定它在非I386 ABIS上做什么,但是掉落此标志似乎是安全的。