手动指定特定链接符号的重新映射

如果不修改这两个源文件,有没有办法通过编译它们来获取生成的目标文件,并说服链接器将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()!