Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
173 views
in Technique[技术] by (71.8m points)

c - weak linking in shared object not working as expected

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.

The shared library, a.c:

#include <stdio.h>

void foo(void); __attribute__((weak))
void bar(void); __attribute__((weak))

void foo(void) {
    printf("called real foo
");
}

void bar(void) {
    printf("called real bar calling
");
    foo();
}

The unit test, b.c:

#include <stdio.h>
#include <stdbool.h>

bool orig_foo;
bool orig_bar;

void __wrap_foo(void) {
    printf("in foo wrapper
");
    if (orig_foo)
            __real_foo();
    else
            printf("called wrapped foo
");
}

void __wrap_bar() {
    printf("in bar wrapper
");
    if (orig_bar)
            __real_bar();
    else
            printf("called wrapped bar
");
}

int main(void) {

    orig_bar = true;
    orig_foo = false;

    printf("calling foo from main
");
    foo();

    printf("
");

    printf("calling bar from main
");
    bar();

    return 0;
}

And finally, the 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

Running a.out produces the following output:

# ./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

From main, the direct call to foo results in __wrap_foo being called, as expected.

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.

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.

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Ld's --wrap works by replacing calls to real functions by calls to their wrappers only in files which are linked with this flag. Your library isn't, so it just does plain foo and bar calls. So they get resolved to where they are implemented (a.so).

As for weak symbols, dynamic linker ignores their weakness and treats them as normal symbols (unless you run with LD_DYNAMIC_WEAK which isn't recommended).

In your particular case (overriding symbols in shared library) you'd probably need to apply --wrap to a.so as well. Or - you could use standard symbol interposition. Say if library-under-test is in libsut.so and you want to replace some functions with custom implementations in libstub.so, link them to driver program in a proper order:

LDFLAGS += -lstub -lsut

Then definitions in libstub.so will prevail over libsut.so ones.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...