共享库中的弱链接无法按预期工作 [英] weak linking in shared object not working as expected

查看:50
本文介绍了共享库中的弱链接无法按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆