The --wrap
in ld
can be emulated by the /ALTERNATENAME
option in MSVC Linker.
We start from two compilation units, say foo.o
compiled from foo.c
, whose external functions are declared in foo.h
, and main.o
from main.c
.
(If foo
has been compiled as a library, things won't change much.)
// 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");
}
The return value of int foo()
is 0, so the snippet of code above will output "original".
Now we override the actual implementation by an alias: The #include "foo.h"
in main.c
is replaced by
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
Let me explain what happens here:
- by
#define foo real_foo
, the function declaration in foo.h
is modified as int real_foo()
.
- However, the symbol in
foo.o
is still named after int foo()
, instead of the alias int real_foo()
. That's why we need the /alternatename
linker switch.
"/alternatename:real_foo=foo"
tells the linker that, if you cannot find the symbol called real_foo
, try foo
again before throwing an error.
- Apparently there is no definition of
int real_foo()
. MSVC Linker will search for int foo()
and link it instead at each occurrence of int real_foo()
.
As the previous implementation has been aliased, now we redirect int foo()
to our new implementation by a macro:
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
And we are done here. At last the main.cpp
looks like:
#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");
}
Built in MSVC, it will output "wrapped".