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

时间:2016-12-10 05:28:29

标签: c linux linker ld symbols

如果不修改这两个源文件,有没有办法通过编译它们来获取生成的目标文件,并说服链接器将main_v1.c中的foo链接到bar.c中的bar

main_v1.c

void foo(void);

int main(void)
{
    foo();
}

bar.c

#include <stdio.h>

void bar(void)
{
    puts("bar()!");
}

修改目标文件本身是公平的游戏,但假设我们甚至可能没有可用的源代码。该平台是Linux。

坚持对main_v1.c进行适度的更改,并链接另外的&#34;映射&#34;目标文件,这是一种几乎只用标准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()本身会在链接后内联,因此还有改进的余地。

1 个答案:

答案 0 :(得分:1)

这将是GNU ld --wrap option

的工作

我们假设你已经编译了main_v1.o,并且可能无法改变 main_v1.c以及bar.o编译的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()!