为了澄清,我的问题是当调用者和被调用者在与GCC编译器和链接器的同一编译单元中定义时,包装/拦截从一个函数/符号到另一个函数/符号的调用.
我的情况类似于以下情况:
/* foo.c */
void foo(void)
{
/* ... some stuff */
bar();
}
void bar(void)
{
/* ... some other stuff */
}
Run Code Online (Sandbox Code Playgroud)
我想包装对这些函数的调用,我可以用ld的--wrap
选项(到某一点)用ld的选项(然后我实现__wrap_foo和__wrap_bar,然后按照ld --wrap
选项的结果调用__real_foo和__real_bar ).
gcc -Wl,--wrap=foo -Wl,--wrap=bar ...
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,这只对来自此编译单元外部的foo和bar的引用生效(并在链接时解析).也就是说,从foo.c中的其他函数调用foo和bar 不会被包装.
我尝试使用objcopy --redefine-sym,但只重命名符号及其引用.
我想将调用替换为foo
和bar
(在foo.o中)__wrap_foo
以及__wrap_bar
(就像它们通过链接器--wrap
选项在其他目标文件中解析一样)之前我将*.o文件传递给链接器的--wrap
选项,而不必修改foo .c的源代码.
这样,包装/拦截发生在所有调用foo
和bar
,而不仅仅是发生在foo.o之外的调用.
这可能吗?
我有一个C文件的静态库,在Cygwin上用g ++编译.我希望单元测试库中定义的一个函数.该函数调用该库中定义的另一个函数,我希望覆盖依赖项以将其替换为我自己的该函数版本.我无法修改静态库中的内容,因此此解决方案[ 覆盖C中的函数调用 ]不适用.
通常,我可以编写.cpp文件并包含.c文件,其中包含我想要单元测试的函数,它实际上使用我添加的代码扩展了该文件.这是一个我从未用于生产代码的肮脏技巧,但它对于单元测试C文件很方便,因为它使我的测试代码能够访问该C文件中的静态内容.然后,我可以写我的假依赖版本,以及调用我正在测试的函数的单元测试函数.我编译my.cpp来获取my.o,然后将其与静态库链接.从理论上讲,由于链接器已经找到了依赖关系的定义(我提供的那个),因此它不会在库中查找,也不会发生冲突.通常这可行,但现在我得到一个"多重定义"错误,链接器首先找到我的假,然后找到真正的假.我不知道是什么原因引起的,不知道该找什么.我也不能把它归结为一个简单的例子,因为我的简单例子没有这个问题.
想法好吗?
我试图在C中覆盖一个函数调用,但是当在同一个编译单元中使用该函数时,我遇到了问题.在下面的代码中,我试图替换函数get_resolution(),但我只能在test.c中完成但不能从display.c中实现它.
// display.c -------------------------------------------------------------
#include <stdio.h>
void get_resolution()
{
printf("Original get_resolution\n");
}
void display()
{
get_resolution();
}
// test.c ----------------------------------------------------------------
#include <stdio.h>
void __wrap_get_resolution()
{
printf("Mock get_resolution\n");
// __real_get_resolution(); // Should be possible to call original
}
int main()
{
display(); // **ISSUE** Original get_resolution() is called
get_resolution(); // __wrap_get_resolution() is called
return 0;
}
// gcc -Wl,--wrap,get_resolution display.c test.c
Run Code Online (Sandbox Code Playgroud)
我的要求是,当我从main()调用display()时,我希望执行__wrap_get_resolution(),但我总是看到正在调用原始的get_resolution().对拆卸的一点分析表明函数get_resolution被不同地调用:
在display() - > get_resolution()的地址已经解析
00000000 <_get_resolution>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 …
Run Code Online (Sandbox Code Playgroud) 如何取消定义库函数以使用我的同一函数版本。请注意,我需要包含同一文件的其他函数的头文件。所以不包括不是一个选择。有没有什么方法可以不改名字就可以使用呢?
我在测试中遇到了这个问题,我仍然不明白给出的答案:
假设我写了以下代码:
#include <math.h>
#include <stdio.h>
float cos(float x){
return 1-x*x/4;
}
int main()
{
printf("%0f",cos(0.05f)+sin(0.05f));
}
Run Code Online (Sandbox Code Playgroud)
让我们假设cos
并sin
在数学库中声明和定义(接收和返回double
),并且我试图将我的代码与数学库链接起来.
另一个假设是cos
定义于math.c
.
问题是:
"代码是否会成功编译/链接?如果是,将调用哪个cos函数?"
答案是:
"是的,代码将编译,我的cos将被调用".
怎么解释这种行为?这些多个定义不是同一个函数吗?
我想在 Windows 中创建一个静态库 (.lib),可以在后续构建中用作未定义函数的“备份”。
例如,假设我有 foobar.lib,它具有以下定义:
FOO
BAR
Run Code Online (Sandbox Code Playgroud)
我还有一些其他程序,FOO
它只定义并且将被构建到一个必须导出的 DLLFOO
和BAR
. 我希望能够使用 foobar.lib 自动导出BAR
生成的 DLL 中的默认定义(并忽略FOO
foobar.lib 中的定义)。
我曾尝试将 foobar.lib 发送到链接器,但出现多个定义的符号错误(/FORCE 应该覆盖它,但强烈警告它可能无法按预期工作)。我也试过使用 /NODEFAULTLIB:foobar.lib 但它完全忽略了库并说BAR
是未定义的。
我几乎 100% 肯定有一种方法可以做到这一点,因为我使用一个执行此操作的应用程序 (Abaqus) 来允许用户编写插件,而不必为插件 DLL 定义所有必需的导出。他们不使用 /FORCE 选项。
使用gcc / ld,我要使用libfoo.a
,其中包含一个符号symbol_foo
(这是一个函数-如果重要的话,请参阅ISR)。其他libfoo
功能显然在使用该功能。我想做的是使用编译我自己的二进制文件libfoo.a
,而是链接自己的版本symbol_foo
。
这可能吗?当前,由于符号的多个定义,我得到ld错误。也就是说,在原始静态库中未将其声明为“软链接”或类似内容。
理想情况下,我希望那里存在类似的__attribute__((ld_override))
东西,但是我猜那里不存在。有任何想法吗?
我正在按照这个答案来覆盖对C库的C函数的调用.
我想我做的一切都正确,但它不起作用:
我想覆盖"DibOpen"功能.这是我在运行应用程序时传递给LD_PRELOAD环境变量的库代码:
DIBSTATUS DibOpen(void **ctx, enum Board b)
{
printf("look at me, I wrapped\n");
static DIBSTATUS (*func)(void **, enum Board) = NULL;
if(!func)
func = dlsym(RTLD_NEXT, "DibOpen");
printf("Overridden!\n");
return func(pContextAddr, BoardType, BoardHdl);
}
Run Code Online (Sandbox Code Playgroud)
nm lib.so | grep DibOpen
节目的输出
000000000001d711 T DibOpen
Run Code Online (Sandbox Code Playgroud)
当我像这样运行我的程序时
LD_PRELOAD=libPreload.so ./program
Run Code Online (Sandbox Code Playgroud)
我program
用-ldl 链接我,但ldd program
没有显示libdl.so的链接
它停止了
symbol lookup error: libPreload.so: undefined symbol: dlsym
Run Code Online (Sandbox Code Playgroud)
.我该怎么做才能进一步调试?我的错误在哪里?