I build a position-independent executable (puppet below), dynamically load via dlopen, get its main via dlsym, and call it. This works fine, as long as this PIE doesn't use iostream, specifically cout. If it does, the code segfaults with the stack trace below.
If I do roughly the same thing, but compile the puppet as a shared library, not a PIE (renaming main to something else), everything works fine.
What could be causing this problem? It exists only on Linux; on a Mac this works fine.
puppet.cpp:
#include <iostream>
int main(int argc, char** argv)
{
std::cout << "Hello from puppet" << std::endl;
}
main.cpp:
#include <iostream>
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
int main()
{
std::cout << "Hello from main" << std::endl;
typedef int (*MainType)(int argc, char *argv[]);
void* lib = dlopen("./puppet", RTLD_LAZY);
if (lib == NULL)
{
std::cerr << "Unable to open the library" << std::endl;
return 1;
}
MainType f = (MainType) dlsym(lib, "main");
if (f == NULL)
{
std::cerr << "Unable to get the function" << std::endl;
return 1;
}
int argc = 0; char** argv = 0;
f(argc, argv);
}
Makefile:
all: main puppet
puppet: puppet.cpp
g++ puppet.cpp -o puppet -fPIE -Wl,-pie -Wl,--export-dynamic
main: main.cpp
g++ main.cpp -o main -ldl
Backtrace from the segfault:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff795da56 in std::ostream::sentry::sentry (this=0x7fffffffe080, __os=...) at /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream.tcc:46
46 /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream.tcc: No such file or directory.
(gdb) back
#0 0x00007ffff795da56 in std::ostream::sentry::sentry (this=0x7fffffffe080, __os=...) at /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream.tcc:46
#1 0x00007ffff795e109 in std::__ostream_insert<char, std::char_traits<char> > (__out=..., __s=__s@entry=0x7ffff6ce0b95 "Hello from puppet", __n=17) at /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/lib
stdc++-v3/include/bits/ostream_insert.h:76
#2 0x00007ffff795e5a9 in std::operator<< <std::char_traits<char> > (__out=..., __s=0x7ffff6ce0b95 "Hello from puppet") at /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/char_t
raits.h:320
#3 0x00007ffff6ce0a87 in main () from ./puppet
#4 0x0000555555554a7e in main ()