Reputation: 163
Environment:
I have two dependent libraries (either static or shared, not sure whether this affects), libA
and libB
. A function foo()
is defined in libA
, and is called in libB
. Now I have my application code app.c
directly call functions from libB
which will eventually call foo()
. A simple workflow is app.c -> libB.a -> libA.a -> foo()
.
However, I want to change how foo()
is implemented for some particular purpose. I hope app.c
can have a magic function, if called, redirecting the call to foo()
to the one provided by app.c
. So the workflow, if could be achieved, should be
app.c -> libB.a -(other than foo())-> libA.a
| /
| (to call foo())
v /
foo()
The embarrassment is that I have fully control on app.c
but minimal or even no access to those libraries. So is it possible to achieve such idea and how?
Update
As mentioned in comments, well missing this can lead to a totally different way of solution, the redirection is better configurable and happens at runtime. This is for test purpose so that normally the workflow should be what it is while only changes itself when testing is performed.
Upvotes: 0
Views: 929
Reputation: 213656
Hopefully clearer statement of the problem: app.c
calls bar()
, which is defined in libB.a
. bar()
calls foo()
, which is defined in libA.a
.
Desired outcome: at runtime, optionally redirect the call to foo()
to an alternate implementation foo_other()
depending on command line argument or environment variable.
Solution (assuming the signature of foo
is int foo(void)
):
app.c
:int foo_other()
{
printf("%s in %s:%d\n", __func__, __FILE__, __LINE__);
return 42;
}
int __real_foo();
int __wrap_foo()
{
printf("%s in %s:%d\n", __func__, __FILE__, __LINE__);
if (getenv("TTT") != NULL) return foo_other();
return __real_foo();
}
gcc app.c libB.a libA.a -Wl,--wrap,foo
Result:
$ ./a.out
bar in bar.c:6
__wrap_foo in main.c:19
foo in foo.c:4
$ TTT=1 ./a.out
bar in bar.c:6
__wrap_foo in main.c:19
foo_other in main.c:13
Obviously you can remove the debug printf
calls and change the mechanism used to switch between real foo()
and foo_other()
as you need.
P.S. For documentation for the linker --wrap
flag, see man ld
.
Example of using --wrap
for mocking.
When using shared libraries, this approach will not work. But a different equivalent approach is available via function interpositioning.
Upvotes: 1