共享库中的弱链接无法按预期工作 [英] weak linking in shared object not working as expected
问题描述
我正在尝试使用 cmocka 单元测试框架,该框架建议使用弱链接来选择用户定义的实现,而不是功能的实际实现.在我的环境中,我有一个要进行单元测试的共享对象.我已经在一个单独的文件中实现了单元测试,我将其编译并链接到共享库.我的问题是,在共享库中调用函数 bar
,然后在该共享库中调用函数 foo
总是导致真正实现 foo 代码>,而不是自定义代码.我已经创建了共享库和单元测试的简化实现.
I'm trying to use the cmocka unit test framework which suggests to use weak linking to be able to select a user-defined implementation over the actual implementation of a function. In my environment I have a shared object which I want to unit test. I've implemented the unit tests in a separate file which I compile and link to the shared object. My problem is that calling a function bar
in the shared object which in turn calls a function foo
in that shared object always leads to the real implementation of foo
and not the custom one. I've created a simplified implementation of the shared object and of the unit test.
共享库 a.c
:
#include <stdio.h>
void foo(void); __attribute__((weak))
void bar(void); __attribute__((weak))
void foo(void) {
printf("called real foo\n");
}
void bar(void) {
printf("called real bar calling\n");
foo();
}
单元测试 b.c
:
#include <stdio.h>
#include <stdbool.h>
bool orig_foo;
bool orig_bar;
void __wrap_foo(void) {
printf("in foo wrapper\n");
if (orig_foo)
__real_foo();
else
printf("called wrapped foo\n");
}
void __wrap_bar() {
printf("in bar wrapper\n");
if (orig_bar)
__real_bar();
else
printf("called wrapped bar\n");
}
int main(void) {
orig_bar = true;
orig_foo = false;
printf("calling foo from main\n");
foo();
printf("\n");
printf("calling bar from main\n");
bar();
return 0;
}
最后是 Makefile
:
all: a.out
a.out: b.c a.so
gcc -Wall b.c a.so -Wl,--wrap=foo -Wl,--wrap=bar
a.so: a.c
gcc -Wall -c a.c -shared -o a.so
clean:
rm -f a.so a.out
运行 a.out
会产生以下输出:
# ./a.out
calling foo from main
in foo wrapper
called wrapped foo
calling bar from main
in bar wrapper
called real bar
called real foo
从主目录直接调用 foo
会导致按预期方式调用 __ wrap_foo
.
From main, the direct call to foo
results in __wrap_foo
being called, as expected.
接下来,我从main调用 bar
,正确地导致调用 __ wrap_bar
,然后将调用重定向到 bar
的实际实现( __ real_bar
).然后, bar
会调用 foo
,但使用的是真正的实现,而不是包装的实现.为什么在这种情况下不调用 foo
的包装实现?该问题似乎与函数调用的来源有关.
Next, I call bar
from main which correctly results in __wrap_bar
being called, where I redirect the call to the real implementation of bar
(__real_bar
). bar
then calls foo
but the real implementation is used, not the wrapped one. Why isn't the wrapped implementation of foo
called in this case? It looks like the issue is related to from where the function call originates.
在函数 bar
中,如果我用 __ wrap_foo
替换了对 foo
的调用,我确实获得了预期的行为,但是我不认为这是一个优雅的解决方案.
In function bar
, if I replaced the called to foo
with __wrap_foo
I do get the expected behaviour however I don't think that this is an elegant solution.
我已经使用普通链接和 dlopen(3)
和朋友设法绕过了这个问题,但是我很好奇为什么弱链接在我的情况下不起作用.
I've managed to bypass this problem using normal linking and dlopen(3)
and friends however I'm curious as to why weak linking isn't working in my case.
推荐答案
在 bar()
中,链接器不存储对 foo()的引用
,但转换单元的 text
部分中的偏移量.因此,该名称会丢失.
In bar()
the linker does not store a reference to foo()
but to an offset in the text
section of the translation unit. Therefore the name is lost.
弱"属性在这里没有帮助.
此外,使用 -ffunction_sections
也无济于事,因为引用将指向 foo()
的该部分的偏移量.
Also it does not help to use -ffunction_sections
because the reference will be to an offset of the section of foo()
.
获得预期结果的一种直接方法是将所有功能分离在各自的翻译单元中.您不需要为此使用单独的源文件,某些条件编译也将有所帮助.但这使来源很难看.
One straight forward way to get the desired result is to separate all functions in their own translation unit. You don't need separated source files for this, some conditional compilation will also help. But it makes the source ugly.
您可能希望研究我对问题的回答也重命名一个函数而不更改其引用" .
这篇关于共享库中的弱链接无法按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!