ld 中的 --wrap 可以通过 MSVC 链接器中的 /ALTERNATENAME 选项进行模拟。
我们从两个编译单元开始,比如从foo.c 编译的foo.o,其外部函数在foo.h 中声明,main.o 从main.c 中声明。
(如果foo 已经编译为库,情况不会有太大变化。)
// foo.h
int foo();
// foo.c
int foo() {
return 0;
}
// main.c
#include <stdio.h>
#include "foo.h"
int main() {
int x = foo();
printf("%s\n", x ? "wrapped" : "original");
}
int foo()的返回值为0,所以上面代码的sn-p会输出“original”。
现在我们用别名覆盖实际的实现:main.c 中的 #include "foo.h" 被替换为
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
让我解释一下这里发生了什么:
-
#define foo real_foo将foo.h中的函数声明修改为int real_foo()。
- 但是,
foo.o 中的符号仍然以int foo() 命名,而不是别名int real_foo()。这就是我们需要 /alternatename 链接器开关的原因。
-
"/alternatename:real_foo=foo" 告诉链接器,如果找不到名为 real_foo 的符号,请在引发错误之前再次尝试 foo。
- 显然没有
int real_foo() 的定义。 MSVC 链接器将搜索 int foo() 并在每次出现 int real_foo() 时链接它。
由于之前的实现已被别名,现在我们通过宏将int foo() 重定向到我们的新实现:
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
我们到这里就完成了。最后main.cpp 看起来像:
#include <stdio.h>
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
int main() {
int x = foo();
printf("%s\n", x ? "wrapped" : "original");
}
内置MSVC,会输出“wrapped”。