使用 C++ 构建一个 .so 这也是一个可执行文件

问题描述

基于 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",__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",__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

谢谢!

解决方法

我刚刚尝试了旧 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::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::allocator<char> >::basic_string()'
/usr/bin/ld: main.cc:(.text+0x8c): undefined reference to `std::__cxx11::basic_string<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 检测并拒绝了它。