如何正确使用`--wrap`选项包装函数?

12

gcc 6.3 的 man 手册中写道:

--wrap=symbol
           Use a wrapper function for symbol.  Any undefined reference to
           symbol will be resolved to "__wrap_symbol".  Any undefined
           reference to "__real_symbol" will be resolved to symbol.
           ...
           If you link other code with this file using --wrap malloc, then all
           calls to "malloc" will call the function "__wrap_malloc" instead.
           The call to "__real_malloc" in "__wrap_malloc" will call the real
           "malloc" function.

所以我创建了一个简单的示例:

#include <stdio.h>

int foo() {
    printf("foo\n");
    return 0;
}

int __wrap_foo() {
    printf("wrap foo\n");
    return 0;
}

int main () {
    printf("foo:");foo();
    printf("wrapfoo:");__wrap_foo();
    printf("realfoo:");__real_foo();
    return 0;
}

并使用以下命令进行编译:

gcc main.c -Wl,--wrap=foo -o main

这给了我一个警告:

main.c:18:21: warning: implicit declaration of function__real_foo[-Wimplicit-function-declaration]
  printf("realfoo:");__real_foo();
                     ^~~~~~~~~~

好的,继续前进。现在我建议输出结果应该像这样:

foo:wrap foo
wrapfoo:wrap foo
realfoo:foo

相反我得到了这个:

foo:foo
wrapfoo:wrap foo
realfoo:foo

希望问题已经清楚了。我对这个警告感到困惑。通常,链接器应该将__real函数链接到foo()。此外,对foo()的调用应该链接到__wrap_foo。但是输出显示,实际执行的是foo()

如何正确使用--wrap


5
确实有效。但是由于您有一个单独的翻译单元,而且foo已经存在,对foo的调用不会造成对foo未定义引用 - StoryTeller - Unslander Monica
我不明白。上面的例子输出似乎有误。foo() 应该输出 "wrap foo"!我做错了什么? - eDeviser
2
你正在忽略"未定义的引用"需求。 - StoryTeller - Unslander Monica
哇喔,就是这样!现在去撰写完整的答案了... - eDeviser
5
个人观点:使用“--wrap”选项的正确方式是根本不使用。这是一种可怕的解决方法,仅在你必须链接某些没有源代码的库时才使用。当其他所有选项都用尽(包括与库供应商交谈,然后与老板交谈并威胁要辞职,如果必须继续使用需要此类恶劣操作的糟糕库)时,这是挽救你的心智健康的最后一招。 - Art
对我来说没问题。我只是使用 --wrap 来创建一些存根和模拟对象,当没有其他选择来实现一些单元测试时。 - eDeviser
1个回答

19

正如StoryTeller告诉我一样,我忽略了我已经发布的“未定义引用”要求:

... 任何对符号的未定义引用将被解析为"__wrap_symbol"。 任何对"__real_symbol"的未定义引用将被解析为符号。

为使用--wrap选项,我重新排列了我的代码示例:

main.c:

#include <stdio.h>
extern int foo();
extern int __real_foo();

int __wrap_foo() {
    printf("wrap foo\n");
    return 0;
}

int main () {
    printf("foo:");foo();
    printf("wrapfoo:");__wrap_foo();
    printf("realfoo:");__real_foo();
    return 0;
}

foo.c:

#include <stdio.h>
int foo() {
    printf("foo\n");
    return 0;
}

然后编译:

gcc main.c foo.c -Wl,--wrap=foo -o main

运行./main后的惊人输出结果为:

foo:wrap foo
wrapfoo:wrap foo
realfoo:foo

技巧是(如果我错了请纠正),编译时未定义foo()__real_foo()的引用。也就是说,它们具有"未定义的引用",这是链接器将foo()链接到__wrap_foo()__real_foo()链接到foo()的要求。


定义外部符号的一种“自动”方法是使用extern typeof (myfunction) __real_myfunction; - undefined

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