Based on building a .so that is also an executable I'm trying o reproduce with C++ and I'm getting a segmentation fault on main program execution.
/* 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)
$
I the definition of "data" is moved from global to local it runs. It seems that global variables are not being initialized.
Can someone explain what happens and what should be done to make it run?
gdb backtrace on code file result:
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
Thanks!
I just tried code from my old answer; it no longer works using a recent GLIBC (I have 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
Using your C++
example, I can't build it with your commands:
$ 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
If I link with g++
(as you should when you have C++
code), then it links fine but fails the same way as C
code does:
$ 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
So I guess the answer is: it wasn't intended to work this way (and worked in the past "by accident"), and now GLIBC detects and rejects it.