如何将函数调用重定向到用户定义的同名函数调用?
How to redirect a function call to a user-defined one of the same name?
环境:
- OS: Ubuntu 16.04
- 编译器:GCC 5.4.0
我有两个依赖库(静态的或共享的,不确定是否影响),libA
和libB
。函数 foo()
在 libA
中定义,并在 libB
中调用。现在我的应用程序代码 app.c
直接从 libB
调用函数,最终会调用 foo()
。一个简单的工作流程是 app.c -> libB.a -> libA.a -> foo()
.
但是,我想更改 foo()
的实现方式以用于某些特定目的。我希望 app.c
可以有一个神奇的功能,如果被调用,将对 foo()
的调用重定向到 app.c
提供的那个。所以工作流程,如果可以实现的话,应该是
app.c -> libB.a -(other than foo())-> libA.a
| /
| (to call foo())
v /
foo()
尴尬的是,我可以完全控制 app.c
但很少甚至无法访问这些库。那么有没有可能实现这样的想法,如何实现呢?
更新
正如评论中所提到的,错过这一点可能会导致完全不同的解决方案,重定向可更好地配置并在运行时发生。这是为了测试目的,因此通常工作流应该是它的样子,而只有在执行测试时才会改变自己。
希望更清楚地说明问题:app.c
调用 bar()
,它在 libB.a
中定义。 bar()
调用 foo()
,它在 libA.a
.
中定义
期望的结果:在运行时,可选将对foo()
的调用重定向到备用实现foo_other()
取决于命令行参数或环境变量。
解决方案(假设foo
的签名是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();
}
- Link您的申请如下:
gcc app.c libB.a libA.a -Wl,--wrap,foo
结果:
$ ./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
显然,您可以删除调试 printf
调用,并根据需要更改用于在真实 foo()
和 foo_other()
之间切换的机制。
P.S。有关链接器 --wrap
标志的文档,请参阅 man ld
.
Example 使用 --wrap
进行模拟。
使用共享库时,此方法将不起作用。但是通过函数插入可以得到一个不同的等价物 approach。
环境:
- OS: Ubuntu 16.04
- 编译器:GCC 5.4.0
我有两个依赖库(静态的或共享的,不确定是否影响),libA
和libB
。函数 foo()
在 libA
中定义,并在 libB
中调用。现在我的应用程序代码 app.c
直接从 libB
调用函数,最终会调用 foo()
。一个简单的工作流程是 app.c -> libB.a -> libA.a -> foo()
.
但是,我想更改 foo()
的实现方式以用于某些特定目的。我希望 app.c
可以有一个神奇的功能,如果被调用,将对 foo()
的调用重定向到 app.c
提供的那个。所以工作流程,如果可以实现的话,应该是
app.c -> libB.a -(other than foo())-> libA.a
| /
| (to call foo())
v /
foo()
尴尬的是,我可以完全控制 app.c
但很少甚至无法访问这些库。那么有没有可能实现这样的想法,如何实现呢?
更新
正如评论中所提到的,错过这一点可能会导致完全不同的解决方案,重定向可更好地配置并在运行时发生。这是为了测试目的,因此通常工作流应该是它的样子,而只有在执行测试时才会改变自己。
希望更清楚地说明问题:app.c
调用 bar()
,它在 libB.a
中定义。 bar()
调用 foo()
,它在 libA.a
.
期望的结果:在运行时,可选将对foo()
的调用重定向到备用实现foo_other()
取决于命令行参数或环境变量。
解决方案(假设foo
的签名是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();
}
- Link您的申请如下:
gcc app.c libB.a libA.a -Wl,--wrap,foo
结果:
$ ./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
显然,您可以删除调试 printf
调用,并根据需要更改用于在真实 foo()
和 foo_other()
之间切换的机制。
P.S。有关链接器 --wrap
标志的文档,请参阅 man ld
.
Example 使用 --wrap
进行模拟。
使用共享库时,此方法将不起作用。但是通过函数插入可以得到一个不同的等价物 approach。