Is there a way to "statically" interpose a shared .so (or .o) library into an executable?
c, c++, gcc, shared-libraries
Solution
It is possible. Learn about shared library interposition:
When a program that uses dynamic libraries is compiled, a list of undefined symbols is included in the binary, along with a list of libraries the program is linked with. There is no correspondence between the symbols and the libraries; the two lists just tell the loader which libraries to load and which symbols need to be resolved. At runtime, each symbol is resolved using the first library that provides it. This means that if we can get a library containing our wrapper functions to load before other libraries, the undefined symbols in the program will be resolved to our wrappers instead of the real functions.
Problem
First of all, consider the following case. Below is a program: ``` // test.cpp extern "C" void printf(const char*, ...); int main() { printf("Hello"); } ``` Below is a library: ``` // ext.cpp (the external library) #include <iostream> extern "C" void printf(const char* p, ...); void printf(const char* p, ...) { std::cout << p << " World!\n"; } ``` Now I can compile the above program and library in two different ways. The first way is to compile the program without linking the external library: ``` $ g++ test.cpp -o test $ ldd test linux-gate.so.1 => (0xb76e8000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7518000) /lib/ld-linux.so.2 (0xb76e9000) ``` If I run the above program, it will print: ``` $ ./test Hello ``` The second way is to compile the program with a link to the external library: ``` $ g++ -shared -fPIC ext.cpp -o libext.so $ g++ test.cpp -L./ -lext -o test $ export LD_LIBRARY_PATH=./ $ ldd test linux-gate.so.1 => (0xb773e000) libext.so => ./libext.so (0xb7738000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb756b000) libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb7481000) /lib/ld-linux.so.2 (0xb773f000) libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb743e000) libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb7421000) $ ./test Hello World! ``` As you can see, in the first case the program uses `printf` from `libc.so`, while in the second case it uses `printf` from `libext.so`. My question is: from the executable obtained as in the first case and the object code of libext (either as .so or .o), is it possible to obtain an executable like in the second case? In other words, is it possible to replace the link to `libc.so` with a link to `libext.so` for all symbols defined in the latter? **Note that interposition via LD_PRELOAD is not what I want. I want to obtain an exectuable which is directly linked to the libraries I need. I underline again that fact the I only have access to the first binary and to the external object I want to "statically" interpose **