gpt4 book ai didi

c - 从同一编译单元覆盖 C 中的函数调用

转载 作者:太空狗 更新时间:2023-10-29 17:23:50 24 4
gpt4 key购买 nike

我正在尝试 Override a function call in C ,但是当在同一个编译单元中使用该函数时,我遇到了一个问题。在下面的代码中,我试图替换函数 get_resolution(),但我只能在 test.c 中而不是在 display.c 中实现它

// display.c -------------------------------------------------------------

#include <stdio.h>

void get_resolution()
{
printf("Original get_resolution\n");
}

void display()
{
get_resolution();
}

// test.c ----------------------------------------------------------------

#include <stdio.h>

void __wrap_get_resolution()
{
printf("Mock get_resolution\n");
// __real_get_resolution(); // Should be possible to call original
}

int main()
{
display(); // **ISSUE** Original get_resolution() is called
get_resolution(); // __wrap_get_resolution() is called
return 0;
}

// gcc -Wl,--wrap,get_resolution display.c test.c

我的要求是,当我从 main() 调用 display() 时,我希望 __wrap_get_resolution() 被执行,但我总是看到原始的 get_resolution() 被调用。对反汇编的一点分析表明函数 get_resolution 的调用方式不同:

在display() -> get_resolution()的地址已经解析了

00000000 <_get_resolution>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 18 sub $0x18,%esp
6: c7 04 24 00 00 00 00 movl $0x0,(%esp)
d: e8 00 00 00 00 call 12 <_get_resolution+0x12>
12: c9 leave
13: c3 ret

00000014 <_display>:
14: 55 push %ebp
15: 89 e5 mov %esp,%ebp
17: 83 ec 08 sub $0x8,%esp
1a: e8 e1 ff ff ff call 0 <_get_resolution>
1f: c9 leave
20: c3 ret
21: 90 nop
22: 90 nop
23: 90 nop

ma​​in()中->get_resolution的地址还没有解析

00000000 <___wrap_get_resolution>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 18 sub $0x18,%esp
6: c7 04 24 00 00 00 00 movl $0x0,(%esp)
d: e8 00 00 00 00 call 12 <___wrap_get_resolution+0x12>
12: c9 leave
13: c3 ret

00000014 <_main>:
14: 55 push %ebp
15: 89 e5 mov %esp,%ebp
17: 83 e4 f0 and $0xfffffff0,%esp
1a: e8 00 00 00 00 call 1f <_main+0xb>
1f: e8 00 00 00 00 call 24 <_main+0x10>
24: e8 00 00 00 00 call 29 <_main+0x15>
29: b8 00 00 00 00 mov $0x0,%eax
2e: c9 leave
2f: c3 ret

现在的问题是,如何防止编译器解析函数display()中使用的get_resolution()的地址,而是使用重定位表,从而在链接阶段覆盖get_resolution()函数?

编辑:

  1. 根据 hroptatyr 的回复,添加 void get_resolution() __attribute__((weak)); 解决了使用 mingw-gcc 时的问题,但在我的目标平台 QNX/ARM/gcc(4.4.2) )
  2. 如果有人能指出一个支持 ARM 目标的好库,即使像函数 Hook 这样的运行时方法也是可以接受的。

最佳答案

只需为此使用预处理器:

void __wrap_get_resolution()
{
/* calling the real one here */
get_resolution();
}

#define get_resolution __wrap_get_resolution

int main()
{
/* the __wrap... gets called */
get_resolution();
...
}

想法是在放置所有需要查看原始函数的代码之后,“重命名”对包装函数的函数调用。

更脏的版本可能是在本地隐藏函数地址,如下所示:

int main()
{
void(*get_resolution)() = __wrap_get_resolution;
get_resolution();
...
}

这个可以工作,但可能会给你一些讨厌的警告。

编辑
尽管在评论中指出不需要更改 display.c,这里的 weak 属性解决方案来自 http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.

/* in display.c */
void __real_get_resolution()
{
...
}
void get_resolution() __attribute__((weak, alias("__real_get_resolution")));

/* in test.c */
void get_resolution()
{
/* this version will take precedence over get_resolution() in display.c */
...
/* lastly call the real thing */
__real_get_resolution();
}

从现在开始,无论您在哪里调用 get_resolution()( 都编译了“强”版本),都会调用包装版本。

关于c - 从同一编译单元覆盖 C 中的函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11758475/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com