Suppose a function int foo(int x) is made available in library libfoo, which I don't control. I do control a codebase which calls foo() many times, in many files.
Now, I would like to insert some logic before actually making a call to foo(). Let's say its "if condition holds call foo, otherwise do something else" (and never mind the details). So far - not a problem. I write a int foo_wrapper(int x) put my logic in there, and call that one instead.
Now for the hard part: I want to not change the code at the call sites. i.e. I still want there to be foo() calls. So:
- No
foo_almost-same-name functions - No macro trickery to replace the call
- No pre-compilation source code generation
Essentially I want most of my compilation units to "not look" at libfoo, but at some translation unit I provide with a wrapper int foo(); and have the implementation in that translation unit actually call libfoo's foo() function. How achievable is this (without twisting myself into knots too hard)?
Additional information about libfoo:
- It is a static library; in the case of a dynamic library, one could play with the library search path and have the wrapper be located instead of the original; and then the wrapper might be able to dynamically locate
libfooitself, load it, and have the originalfoosymbol available for use when necessary. - I'm working on Linux, and being cross-platform is not a requirement; of course it's always nice to maintain that.
Note: A solution which also works for C code is preferable but not required.
Trivially achievable given the Linux-only constraint.
If
libfoowas a shared library, this is exactly what library interposers do usingLD_PRELOADand similar tricks.But since
libfoois an archive library, all you need to do is rename all your unresolved references fromfootofoo_wrapper. You can do that by runningobjcopy --redefine-sym foo=foo_wrapper caller.o new_caller.o, wherecaller.ois your object file that was originally callingfoo, and linking your binary usingnew_caller.o.(Obviously your can do "update in place" with something like
objcopy ... caller.o /tmp/$$.o && mv /tmp/$$.o caller.o, so you don't have to actually modify your link line.)You will have to repeat this for every object in your codebase.
P.S. Using a macro to achieve the exact same result is probably much simpler -- all you have to do is use
-Dfoo=foo_wrapperon compilation command line. Not sure whether that counts as "macro trickery" in your book.