Without modifying these two source files, is there a way to take the object files produced by compiling them, and convincing a linker to link foo
in main_v1.c to bar
in bar.c?
main_v1.c
void foo(void);
int main(void)
{
foo();
}
bar.c
#include <stdio.h>
void bar(void)
{
puts("bar()!");
}
Modifying the object files themselves is fair game but assume that we might not even have the source code available. The platform is Linux.
By insisting on a modest change to main_v1.c, and linking in an additional "mapping" object file, here's a way to almost get the desired result with just standard C.
main_v2.c
extern void (*const foo)(void);
int main(void)
{
foo();
}
bar.c is unchanged.
map.c
void bar(void);
void (*const foo)(void) = bar;
If the object files are compiled with lto, the function pointer dereference is even elided (using a recent gcc). This is a pretty good result but if main()
is modified to have a direct call to bar()
, then bar()
itself is inlined after linking so there's room for improvement.
This would be a job for the GNU ld
--wrap
option
You have, we assume, a main_v1.o
compiled and perhaps unchangeable from your
main_v1.c
and likewise a bar.o
compiled from your bar.c
.
Now write another source file:
wrap.c
extern void bar(void);
void __wrap_foo(void)
{
bar();
}
Compile it to wrap.o
and link it with the prior object files like so:
$ gcc -c wrap.c
$ gcc -o prog -Wl,--wrap=foo main_v1.o bar.o wrap.o
Then:
$ ./prog
bar()!