如何在 C 中包装现有函数

How to wrap existing function in C

我正在尝试包装现有函数。

以下代码完美运行。

#include<stdio.h>

int __real_main();

int __wrap_main()
{
    printf("Wrapped main\n");
    return __real_main();
}

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

命令:

gcc main.c -Wl,-wrap,main

输出:

Wrapped main
main

所以我用temp改变了main函数。我的目标是包装 temp() 函数。

下面是代码

temp.c

#include<stdio.h>

int temp();

int __real_temp();

int __wrap_temp()
{
    printf("Wrapped temp\n");
    return __real_temp();
}

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

int main()
{
    temp();
    return 0;
}

命令:

gcc temp.c -Wl,-wrap,temp

输出:

temp

包装的临时文件未打印。请指导我包装函数温度。

ld 的联机帮助页说:

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

此处关键字未定义

如果你把定义 temp 放在与使用它的代码相同的翻译单元中,它就不会在使用它的代码中被取消定义。

您需要拆分代码定义和使用它的代码:

#!/bin/sh

cat > user.c  <<'EOF'
#include<stdio.h>

int temp(void);

int __real_temp(void);

int __wrap_temp()
{
    printf("Wrapped temp\n");
    return __real_temp();
}
int main()
{
    temp();
    return 0;
}
EOF

cat > temp.c <<'EOF'
#include<stdio.h>
int temp()
{
    printf("temp\n");
    return 0;
}
EOF


gcc user.c  -Wl,-wrap,temp temp.c  # OK
./a.out

将构建分成两个单独的编译可能会更清楚:

$ gcc -c user.c
$ gcc -c temp.c
$ nm user.o temp.o

temp.o:
                 U puts
0000000000000000 T temp

user.o:
0000000000000015 T main
                 U puts
                 U __real_temp
                 U temp
0000000000000000 T __wrap_temp

现在由于 tempuser.c 中未定义,链接器可以对其施展其 __real_/__wrap_ 魔法。

$ gcc  user.o temp.o  -Wl,-wrap=temp
$ ./a.out
  Wrapped temp
  temp

如果您可以将要覆盖的函数与调用它的函数分开,则 PSCocik 提出的答案非常有效。但是,如果您想将被调用方和调用方保留在同一个源文件中,则 --wrap 选项将不起作用。

相反,您可以在被调用方的实现之前使用 __attribute__((weak)),以便让其他人重新实现它,而不用 GCC 大声疾呼多个定义。

例如,假设您想在以下 hello.c 代码单元中模拟 world 函数。您可以在属性前添加以便能够覆盖它。

#include "hello.h"
#include <stdio.h>

__attribute__((weak))
void world(void)
{
    printf("world from lib\n");
}

void hello(void)
{
    printf("hello\n");
    world();
}

然后您可以在另一个单元文件中覆盖它。非常有用的单位 testing/mocking:

#include <stdio.h>
#include "hello.h"

/* overrides */
void world(void)
{
    printf("world from main.c\n");
}

int main(void)
{
    hello();
    return 0;
}