There is a large number of questions on SO about how to execute a library or dynamically load an executable. As far as I can tell, all the answers come down to: compile your executable as position-independent code and load it with dlopen
. This worked great --- and still works great on macOS --- until a recent change in glibc, which explicitly disabled dlopen
ing PIEs. This change is now in the current version of glibc (2.30) on ArchLinux, for example, and trying to dlopen
a position-independent executable gives an error: "cannot dynamically load position-independent executable".
It's difficult to guess what prompted such a radical change that breaks so much code and useful use cases. (The explanations on Patchwork and Bugzilla don't make much sense to me.) But there is now a question: what to do if you want to create an executable that's also a dynamic library, or vice versa?
A solution was linked from one of the comments. Reproducing it here for posterity:
#include <stdio.h>
#include <unistd.h>
const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux-x86-64.so.2";
extern "C" {
void lib_entry(void)
{
printf("Entry point of the service library
");
_exit(0);
}
}
Compiling with g++ -shared test-no-pie.cpp -o test-no-pie -Wl,-e,lib_entry
produces a shared object (dynamic library) that can also be executed on Linux.
I have two questions:
- What if I want to pass command-line arguments? How to modify this solution so it accepts
arc,argv
? - Are there other alternatives?