【问题标题】:building a .so that is also an executable with C++构建一个.so,它也是 C++ 的可执行文件
【发布时间】:2021-06-18 21:15:39
【问题描述】:

基于building a .so that is also an executable,我正在尝试使用 C++ 进行重现,但在主程序执行时遇到了分段错误。

/* pie.cpp */
#include <cstdio>
int foo()
{
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return 42; 
}
int main() 
{ 
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return foo(); 
}

/* pie.h */
#ifndef PIE_H
#define PIE_H

int foo();

#endif

/* main.cpp */
#include <cstdio>
#include <string>
#include "pie.h"

std::string data;

int main() 
{
  data="TEST"; 
  printf("in %s %s:%d [%s]\n", __func__, __FILE__, __LINE__, data.c_str());
  return foo(); 
}


$ g++ -fPIC -pie -o pie.so pie.cpp -Wl,-E
$ g++ main.cpp ./pie.so


$ ./pie.so
in main pie.cpp:10
in foo pie.cpp:5
$ ./a.out
Segmentation fault (core dumped)
$

我将“数据”的定义从全局移动到它运行的本地。 似乎全局变量没有被初始化。

有人可以解释发生了什么以及应该做些什么来让它运行吗?

代码文件结果的gdb回溯:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  std::string::size (this=0x404080 <data>) at /usr/src/debug/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.h:716
716       { return _M_rep()->_M_length; }
(gdb) bt
#0  std::string::size (this=0x404080 <data>) at /usr/src/debug/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.h:716
#1  std::string::assign (this=0x404080 <data>, __s=0x402010 "TEST", __n=4) at /usr/src/debug/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.tcc:262
#2  0x00000000004011c5 in main () at main.cpp:9

谢谢!

【问题讨论】:

  • 全局未初始化变量存储在 .bss 部分。如果在本地定义,变量存储在堆栈中。这就是区别。
  • 构建一个调试版本并在调试器中运行它,看看有什么问题。我建议将data.c_str() 的结果分配给一个变量,并将此变量用于printf,以便更轻松地检查值。
  • 感谢 Emre İriş。我知道,但问题是为什么在这种情况下会出现段错误?
  • @Bado,我添加了回溯核心文件的gdb结果以供参考。对于我在字符串中看到的段错误,但是为什么呢?
  • glibc 开发人员几年前决定不再支持带有入口点的.sos。不写这个作为答案,因为显然我把我的书签放错了邮件列表讨论的地方。

标签: c++ linux shared-libraries glibc dlopen


【解决方案1】:

我刚刚尝试了旧 answer 的代码;它不再使用最近的 GLIBC(我有 2.31-9+build1):

$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E
$ gcc main.c ./pie.so

$ ./pie.so
in main pie.c:10
in foo pie.c:5

$ ./a.out
./a.out: error while loading shared libraries: ./pie.so: cannot dynamically load position-independent executable

使用您的 C++ 示例,我无法使用您的命令构建它:

$ g++ -fPIC -pie -o pie.so pie.cc -Wl,-E
$ gcc main.cc ./pie.so
/usr/bin/ld: /tmp/ccaXra73.o: in function `main':
main.cc:(.text+0x13): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(char const*)'
/usr/bin/ld: main.cc:(.text+0x1f): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str() const'
/usr/bin/ld: /tmp/ccaXra73.o: in function `__static_initialization_and_destruction_0(int, int)':
main.cc:(.text+0x77): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()'
/usr/bin/ld: main.cc:(.text+0x8c): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
collect2: error: ld returned 1 exit status

如果我与g++ 链接(当你有C++ 代码时应该这样做),那么它链接正常,但失败的方式与C 代码相同:

$ g++ main.cc ./pie.so

$ ./pie.so
in main pie.cc:9
in foo pie.cc:4

$ ./a.out
./a.out: error while loading shared libraries: ./pie.so: cannot dynamically load position-independent executable

所以我猜答案是:它不打算以这种方式工作(并且在过去“偶然”工作),现在 GLIBC 检测并拒绝它。

【讨论】:

  • 感谢@Employed 俄语。编译 main 时应该说 g++。我更正了样本。我遇到了分段错误,但我使用的是 glib 2.17。所以,我想新版本会检测到这一点,现在拒绝它而不是 Seg Fault。
  • glibc 2.30 似乎添加了一个检查以不允许加载 PIE 对象(elixir.bootlin.com/glibc/glibc-2.30/source/elf/dl-load.c 第 1204 行用于检查,第 1218 行用于消息)。
猜你喜欢
  • 2010-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-03
  • 1970-01-01
  • 2013-01-30
相关资源
最近更新 更多