拦截并转发C调用到第三方库

4
我有一个应用程序(A),它调用第三方共享库(C)。我想编写一个自己的库(B),拦截A对C的调用,在某些情况下用自己的代码替换调用,在某些情况下执行一些额外的处理,然后调用C中匹配的函数,有些情况下则直接将调用转发给C。
该应用程序是开源的,因此我可以更改每个调用站点以调用B中的同名函数,然后在需要时调用相应的C函数,但这将是很多工作,并且会使合并上游更改变得困难。我没有第三方库的源代码。如果它是仅头文件,则可以使用命名空间来实现此目标,但我不确定当我自己的库和第三方库似乎都需要定义完全相同的符号时该怎么做。
这种方法是否可行?我主要针对OS X,但希望它也适用于Linux,最终也适用于Windows。

你没有说明你使用的工具链是什么。不知道其他工具链,但GNU ld有--wrap选项,这是实现你想要的一种方式。从ld参考手册中描述的--wrap symbol:"为symbol使用包装器函数。对symbol的任何未定义引用都将解析为__wrap_symbol。对__real_symbol的任何未定义引用都将解析为symbol。这可用于为系统函数提供包装器。" - kaylum
可以做到,我已经做过了 :) 不过需要大量的工作。基本上,你需要从.o文件中提取符号信息,并用你自己创建的“thunk”替换所有未定义的符号。诀窍是保留参数,在未知函数的一般情况下,你将不得不在ASM中进行thunk操作。 - SergeyA
使用#define来重定向库函数调用?例如#define strchr mystrchr - Weather Vane
2个回答

6

至少在Linux上LD_PRELOAD可以工作,但我不能确定在OS X上是否可行。 - Henrik Carlqvist

2
一种解决方案如下:
在头文件中,将您想要拦截的所有函数的#define定义为包装函数。
#define foo wrap_foo
#define bar wrap_bar

将以下内容放入一个在所有代码中都被包含的头文件中,以便所有代码都包含此头文件。这个头文件应该在你要拦截的库的头文件之前被包含。gcc还有一个-include选项,可以导致一个头文件被包含在所有源文件中。
这里的目标是用包装函数替换所有对实际函数的调用。
现在在某个地方定义你的包装函数,并根据需要拦截调用。这个文件不应该包含你之前创建的包装头文件。
int wrap_foo() {
    return foo();
}

int wrap_bar() {
    return bar();
}

将所有内容链接在一起。

请注意,这将允许您仅在包括包装头文件的编译代码中截取对foo()bar()等的调用。任何预编译代码(在库或对象中)将直接链接到foo()bar()等。


谢谢,好主意!虽然这在应用程序中有些侵入性,但我应该能够以一种使合并无缝的方式来实现它。 - user1832047

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接