我有一个带-ffunction-sections选项的gcc编译的目标文件。我可以访问源文件,但不允许修改它。
file.c
void foo(void)
{
bar();
}
void bar(void)
{
abc();
}
我要实现的目的是使对bar的所有引用都采用一个绝对地址(我将在链接器脚本中分配该地址),而bar将由链接器放置在其他某个地址。
一个可能的解决方案是将bar重命名为file_bar而不更改对foo()中的bar的调用。我尝试使用objcopy -redefine-syms,但似乎甚至重命名了对bar的调用。
除非功能在同一编译单元中,否则忙蜂提供的解决方案可以解决该问题。 foo1.c
#include <stdio.h>
extern void bar1();
void foo1(){
printf("foo1\n");
}
int main(){
printf("main\n");
foo1();
bar1();
}
bar1.c
#include <stdio.h>
void bar1(){
printf("bar1\n");
}
wrapper.c
#include <stdio.h>
void __wrap_foo1(){
printf("wrap_foo1\n");
}
void __wrap_bar1(){
printf("wrap_bar1\n");
}
现在
$ gcc -c -ffunction-sections foo1.c bar1.c wrapper.c
$ gcc -Wl,--wrap=foo1 -Wl,--wrap=bar1 -o output foo1.o bar1.o wrapper.o
$ ./output
main
foo1
wrap_bar1
答案 0 :(得分:1)
链接器具有选项“ --wrap”,该选项将对符号“ xxx”的所有引用替换为“ __wrap_xxx”,并将符号本身替换为“ __real_xxx”。它用于在调用和函数之间放置包装函数,作为“拦截器”。
但是,使用此选项,您可以对链接脚本中的这些符号进行任何操作。您只需要用符号定义“ __wrap_xxx”,以便引用可以解析。
根据您的需要,您还可以编写一个甚至不调用“ __real_xxx()”的伪函数“ __wrap_xxx()”。或者,您可以在向量表中放置“ __real_xxx”,或者...无论您想到什么。
我浏览了发表在评论中的OP的the other question的答案。这给了我一个弱化所涉及符号并通过链接器用值覆盖它们的想法。
此示例可能会给您一些启示。我在具有address space layout randomization的Linux上进行了测试,因此所有地址都是随机基数的偏移量。但是对于OP的目标系统,它应该可以按预期工作。
foo1.c
由于重定向地址具有任意值,因此无法调用函数。但是该程序可以打印其地址。
#include <stdio.h>
void foo1(void) {
}
extern void bar1(void);
int main(void) {
printf("%p\n", main);
printf("%p\n", foo1);
printf("%p\n", bar1);
return 0;
}
bar1.c
void bar1(void) {
}
wrapper.ld
这是第一种为链接器提供要使用的地址的方法,即附加的链接器脚本。对于第二个,请参见下文。标准链接描述文件将在此处进行扩展,无需复制和打补丁。由于结构简单,这可能是提供许多可以轻松自动化的重定向地址的最简单方法。
foo1 = 0x1000;
bar1 = 0x2000;
注意:这不是C!正是“链接程序脚本”语法非常相似。
我如何构建和测试
此命令序列可以自动进行排序,以适合您的喜好。尤其是objcopy
的调用可以通过对列表的某些循环来完成。
gcc -c -ffunction-sections foo1.c
objcopy --weaken-symbol=foo1 foo1.o foo2.o
gcc -c -ffunction-sections bar1.c
objcopy --weaken-symbol=bar1 bar1.o bar2.o
gcc foo1.o bar1.o -o original
echo original
./original
gcc foo2.o bar2.o -o weakened
echo weakened
./weakened
gcc foo2.o bar2.o wrapper.ld -o redirected
echo redirected
./redirected
也可以在命令行上给出符号定义,而不是附加的链接描述文件。这是上述第二种选择。
gcc foo2.o bar2.o -Wl,--defsym=foo1=0x1000 -Wl,--defsym=bar1=0x2000 -o redirected
顺便说一句,链接器可以理解@file
从文件file
中读取所有参数。因此,链接器命令的大小没有限制。
除了提供即时值外,您当然还可以提供替代功能。这与上面的工作原理相同,但是您无需编写其他链接程序脚本或符号定义,而是编写源文件。
wrapper.c
是的,没错,名字等于原件的名字!因为我们将原始函数的符号设置为 weak ,所以当链接器用新函数的地址覆盖引用时,链接器不会收到任何错误消息。
void foo1(void) {
}
void bar1(void) {
}
以这种方式构建重定向程序(仅显示新命令):
gcc -c -ffunction-sections wrapper.c
gcc foo2.o bar2.o wrapper.o -o redirected
static
好吧,根据您的目标体系结构,可能将无法实现。这是因为引用的重定位条目。这将是一种相对的关系,它告诉链接器通过对函数部分的偏移进行解析,而不是通过函数的符号进行解析。
我没有对此做进一步的调查。