澄清一下,我的问题是指当使用GCC编译器和链接器在同一个编译单元中定义调用者和被调用者时,从一个函数/符号到另一个函数/符号的包装/拦截调用
我的情况类似于以下情况:
/* foo.c */
void foo(void)
{
/* ... some stuff */
bar();
}
void bar(void)
{
/* ... some other stuff */
}
我想包装对这些函数的调用,我可以使用ld's --wrap
option来实现(到某一点)(然后我实现__wrap_foo和__wrap_bar,它依次调用__real_foo和__real_bar,因为结果是ld的--wrap
选项。)
gcc -Wl,--wrap=foo -Wl,--wrap=bar ...
我遇到的问题是,这仅对foo的引用生效,并且在此编译单元外部来自(并在链接时解析)。也就是说,从foo.c 中的其他函数调用foo和bar不会被包装。
我尝试使用objcopy --redefine-sym,但只重命名符号及其引用。
我想将foo
和bar
(在foo.o内)的调用替换为__wrap_foo
和__wrap_bar
(就像它们在其他目标文件中被解析一样)在我将* .o文件传递给链接器的--wrap
选项之前,链接器的--wrap
选项),而无需修改foo.c的源代码。
这样,对foo
和bar
的所有调用都会进行包装/拦截,而不仅仅是在foo.o之外发生的调用。
这可能吗?
答案 0 :(得分:13)
你必须使用objcopy削弱和全球化符号。
-W symbolname
--weaken-symbol=symbolname
Make symbol symbolname weak. This option may be given more than once.
--globalize-symbol=symbolname
Give symbol symbolname global scoping so that it is visible outside of the file in which it is defined. This option may be given more than once.
这对我有用
bar.c:
#include <stdio.h>
int foo(){
printf("Wrap-FU\n");
}
foo.c的:
#include <stdio.h>
void foo(){
printf("foo\n");
}
int main(){
printf("main\n");
foo();
}
编译
$ gcc -c foo.c bar.c
弱化foo符号并使其成为全局符号,因此它可以再次用于链接器。
$ objcopy foo.o --globalize-symbol=foo --weaken-symbol=foo foo2.o
现在,您可以将新的obj与bar.c的包装链接起来
$ gcc -o nowrap foo.o #for reference
$ gcc -o wrapme foo2.o bar.o
测试
$ ./nowrap
main
foo
包裹的那个:
$ ./wrapme
main
Wrap-FU
答案 1 :(得分:8)
#include <stdio.h>
#include <stdlib.h>
//gcc -ggdb -o test test.c -Wl,-wrap,malloc
void* __real_malloc(size_t bytes);
int main()
{
int *p = NULL;
int i = 0;
p = malloc(100*sizeof(int));
for (i=0; i < 100; i++)
p[i] = i;
free(p);
return 0;
}
void* __wrap_malloc(size_t bytes)
{
return __real_malloc(bytes);
}
然后只需编译此代码并进行调试。当你调用reall malloc时,调用的函数__wrap_malloc和__real_malloc将调用malloc。
我认为这是拦截电话的方式。
基本上是ld。
提供的--wrap选项答案 2 :(得分:6)
您可以在执行被调用者之前使用__attribute__((weak))
,以便让某人重新实现它而不会让GCC对多个定义大吼大叫。
例如,假设您要在以下 hello.c 代码单元中模拟world
函数。您可以添加属性以便能够覆盖它。
#include "hello.h"
#include <stdio.h>
__attribute__((weak))
void world(void)
{
printf("world from lib\n");
}
void hello(void)
{
printf("hello\n");
world();
}
然后您可以在另一个单元文件中覆盖它。对于单元测试/模拟非常有用:
#include <stdio.h>
#include "hello.h"
/* overrides */
void world(void)
{
printf("world from main.c"\n);
}
void main(void)
{
hello();
return 0;
}
答案 3 :(得分:5)
这似乎按照记录的方式运作:
--wrap=symbol
Use a wrapper function for symbol.
Any undefined reference to symbol will be resolved to "__wrap_symbol". ...
请注意上面的未定义。当链接器处理foo.o
时,bar()
未未定义,因此链接器不会将其包装。我不确定为什么以这种方式完成,但可能有一个用例需要这样做。
答案 4 :(得分:4)
如果您将--undefined
与--wrap
-u SYMBOL, --undefined SYMBOL
Start with undefined reference to SYMBOL
答案 5 :(得分:3)
我尝试了solution中的@PeterHuewe,它可以工作,但是不允许从包装器调用原始函数。为此,我的解决方案如下:
foo.c
#include <stdio.h>
void foo(){
printf("This is real foo\n");
}
int main(){
printf("main\n");
foo();
}
foo_hook.c
#include <stdio.h>
void real_foo();
int foo(){
printf("HOOK: BEFORE\n");
real_foo();
printf("HOOK: AFTER\n");
}
制作文件
all: link
link: hook
gcc -o wo_hook foo.o
gcc -o w_hook foo_hooked.o foo_hook.o
hook: build_o
objcopy \
foo.o \
--add-symbol real_foo=.text:$(shell objdump -t foo.o | grep foo | grep .text | cut -d' ' -f 1),function,global \
--globalize-symbol=foo \
--weaken-symbol=foo \
foo_hooked.o
build_o:
gcc -c foo.c foo_hook.c
clean:
-rm w_hook wo_hook *.o
示例
virtualuser@virtualhost:~/tmp/link_time_hook$ make
gcc -c foo.c foo_hook.c
objcopy foo.o \
--add-symbol real_foo=.text:0000000000000000,function,global \
--globalize-symbol=foo \
--weaken-symbol=foo \
foo_hooked.o
gcc -o wo_hook foo.o
gcc -o w_hook foo_hooked.o foo_hook.o
virtualuser@virtualhost:~/tmp/link_time_hook$ ls
Makefile foo.c foo.o foo_hook.c foo_hook.o foo_hooked.o w_hook wo_hook
virtualuser@virtualhost:~/tmp/link_time_hook$ ./w_hook
main
HOOK: BEFORE
This is real foo
HOOK: AFTER
virtualuser@virtualhost:~/tmp/link_time_hook$
virtualuser@virtualhost:~/tmp/link_time_hook$ ./wo_hook
main
This is real foo
virtualuser@virtualhost:~/tmp/link_time_hook$
答案 6 :(得分:0)
使用链接器
$ /usr/bin/ld --version
GNU ld (GNU Binutils for Ubuntu) 2.30
我可以使用defsym
选项解决该问题:
--defsym SYMBOL=EXPRESSION Define a symbol`
代替
gcc -Wl,--wrap=foo -Wl,--wrap=bar ...
尝试
gcc -Wl,--defsym,foo=__wrap_foo -Wl,--defsym,bar=__wrap_bar ...
我也没有尝试定义__real_*
符号。