手动指定特定链接符号的重新映射
如果不修改这两个源文件,有没有办法通过编译它们来获取生成的目标文件,并说服链接器将main_v1.c中的foo
链接到bar.c中的bar
?
main_v1.c
void foo(void); int main(void) { foo(); }
bar.c
#include void bar(void) { puts("bar()!"); }
修改目标文件本身是公平的游戏,但假设我们甚至可能没有可用的源代码。 该平台是Linux。
通过坚持对main_v1.c的适度更改,并链接到一个额外的“映射”对象文件,这里几乎可以用标准C获得所需的结果。
main_v2.c
extern void (*const foo)(void); int main(void) { foo(); }
bar.c没有变化。
map.c
void bar(void); void (*const foo)(void) = bar;
如果使用lto编译目标文件,则甚至可以省略函数指针取消引用(使用最近的gcc)。 这是一个非常好的结果但是如果修改main()
以直接调用bar()
,那么bar()
本身在链接后内联,因此还有改进的余地。
这将是GNU ld
--wrap
选项的工作
我们假设你有一个main_v1.o
编译过,也许你的main_v1.c
可能无法main_v1.c
,同样也是main_v1.c
编译的bar.c
现在写另一个源文件:
wrap.c
extern void bar(void); void __wrap_foo(void) { bar(); }
将它编译为wrap.o
并将其与之前的目标文件链接,如下所示:
$ gcc -c wrap.c $ gcc -o prog -Wl,--wrap=foo main_v1.o bar.o wrap.o
然后:
$ ./prog bar()!