lui*_*nal 33 linker gcc mocking ld interceptor
为了澄清,我的问题是当调用者和被调用者在与GCC编译器和链接器的同一编译单元中定义时,包装/拦截从一个函数/符号到另一个函数/符号的调用.
我的情况类似于以下情况:
/* foo.c */
void foo(void)
{
/* ... some stuff */
bar();
}
void bar(void)
{
/* ... some other stuff */
}
Run Code Online (Sandbox Code Playgroud)
我想包装对这些函数的调用,我可以用ld的--wrap
选项(到某一点)用ld的选项(然后我实现__wrap_foo和__wrap_bar,然后按照ld --wrap
选项的结果调用__real_foo和__real_bar ).
gcc -Wl,--wrap=foo -Wl,--wrap=bar ...
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,这只对来自此编译单元外部的foo和bar的引用生效(并在链接时解析).也就是说,从foo.c中的其他函数调用foo和bar 不会被包装.
我尝试使用objcopy --redefine-sym,但只重命名符号及其引用.
我想将调用替换为foo
和bar
(在foo.o中)__wrap_foo
以及__wrap_bar
(就像它们通过链接器--wrap
选项在其他目标文件中解析一样)之前我将*.o文件传递给链接器的--wrap
选项,而不必修改foo .c的源代码.
这样,包装/拦截发生在所有调用foo
和bar
,而不仅仅是发生在foo.o之外的调用.
这可能吗?
小智 15
您必须使用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.
Run Code Online (Sandbox Code Playgroud)
这对我有用
bar.c:
#include <stdio.h>
int foo(){
printf("Wrap-FU\n");
}
Run Code Online (Sandbox Code Playgroud)
foo.c的:
#include <stdio.h>
void foo(){
printf("foo\n");
}
int main(){
printf("main\n");
foo();
}
Run Code Online (Sandbox Code Playgroud)
编译它
$ gcc -c foo.c bar.c
Run Code Online (Sandbox Code Playgroud)
削弱foo符号并使其成为全局符号,因此它可以再次用于链接器.
$ objcopy foo.o --globalize-symbol=foo --weaken-symbol=foo foo2.o
Run Code Online (Sandbox Code Playgroud)
现在,您可以将新的obj与bar.c中的包装链接起来
$ gcc -o nowrap foo.o #for reference
$ gcc -o wrapme foo2.o bar.o
Run Code Online (Sandbox Code Playgroud)
测试
$ ./nowrap
main
foo
Run Code Online (Sandbox Code Playgroud)
包裹的一个:
$ ./wrapme
main
Wrap-FU
Run Code Online (Sandbox Code Playgroud)
Rit*_*esh 10
#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);
}
Run Code Online (Sandbox Code Playgroud)
然后只需编译此代码并进行调试.当你调用reall malloc时,调用的函数__wrap_malloc和__real_malloc将调用malloc.
我认为这是拦截电话的方式.
基本上它是由ld提供的--wrap选项.
小智 6
您可以__attribute__((weak))
在被调用者实施之前使用,以便让某人重新实现它而不会让GCC大肆宣传多个定义.
例如,假设您要world
在以下hello.c代码单元中模拟该函数.您可以添加属性以便能够覆盖它.
#include "hello.h"
#include <stdio.h>
__attribute__((weak))
void world(void)
{
printf("world from lib\n");
}
void hello(void)
{
printf("hello\n");
world();
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以在另一个单元文件中覆盖它.对单元测试/模拟非常有用:
#include <stdio.h>
#include "hello.h"
/* overrides */
void world(void)
{
printf("world from main.c"\n);
}
void main(void)
{
hello();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这看起来像记录的那样:
--wrap=symbol
Use a wrapper function for symbol.
Any undefined reference to symbol will be resolved to "__wrap_symbol". ...
Run Code Online (Sandbox Code Playgroud)
注意上面的undefined.当连接过程foo.o
中,bar()
是不是不确定的,因此链接不包裹.我不确定为什么这样做,但可能有一个用例需要这个.
小智 5
我已经尝试了@PeterHuewe的解决方案,它有效,但它不允许从包装器调用原始函数。为了实现这一点,我的解决方案如下:
foo.c
#include <stdio.h>
void foo(){
printf("This is real foo\n");
}
int main(){
printf("main\n");
foo();
}
Run Code Online (Sandbox Code Playgroud)
foo_hook.c
#include <stdio.h>
void real_foo();
int foo(){
printf("HOOK: BEFORE\n");
real_foo();
printf("HOOK: AFTER\n");
}
Run Code Online (Sandbox Code Playgroud)
生成文件
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
Run Code Online (Sandbox Code Playgroud)
例子
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$
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
24037 次 |
最近记录: |