The one header library to allow statically linked binaries to get access to the dynamic loading functionality.
The trick for doing this is to make the application do part of the kernel job
and load the dynamic linker manually. This has the additional benefit of making
the application libc version independent. The path to the linker is found
using an assumption that on each Linux machine there is a dynamically linked
/bin/sh binary from which the system's linker path can be obtained. Assuming
this holds on all distributions, this also makes the application linker
independent.
Since the system libc is loaded separately, this means the applications can
still use statically linked libc such as musl without issues.
For doing all of the preparatory work, the library needs some space to store data required for the dynamic linker to launch properly. Trying to take as little space as possible and be non-intrusive as possible, the library allocates all of the permanent data on the stack in a tightly packed manner. This uses ~2K (depends on the number of args and env vars present) of the stack space which is just a small percentage of the usual stack on linux.
Note
Currently only x86_64 and aarch64 are supported
Just include the header to your application and ensure the main function signature is
int main(int argc, char** argv)The access to the dlopen and other functions just access the sd_got global.
There is also a SD_RTLD_NOW macro already defined to avoid including additional headers.
void* libc = sd_got.dlopen("libc.so.6", SD_RTLD_NOW);The sd_got itself contains 4 function pointers: dlopen, dlsym,
dlclose, dlerror:
typedef struct {
sd_dlopen_fn dlopen;
sd_dlsym_fn dlsym;
sd_dlclose_fn dlclose;
sd_dlerror_fn dlerror;
} sd_got_t;The loading of the dynamic linker happens before the main is called. For this
reason the library defines its own _start symbol from which the program
execution should start. For this to work, build must include compilation flags:
-nostartfiles -fno-stack-protector.
There is an example static_dynamic_test.c with build.sh that shows all of this and
builds a simple raylib demo with this functionality
- Detour - provided the base idea of how this whole machinery should work