C で関数呼び出しをオーバーライドしようとしていますが、関数が同じコンパイル単位で使用されているときに問題に直面しています。以下のコードでは、関数 get_resolution() を置き換えようとしていますが、display.c ではなく test.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
main() 内 -> 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() 関数をオーバーライドできるようにする方法です。
編集:
- hroptatyr の応答に基づいて、追加
void get_resolution() __attribute__((weak));
すると、mingw-gcc を使用する場合の問題は解決しますが、ターゲット プラットフォーム QNX/ARM/gcc(4.4.2) では解決しません。 - 関数フックのような実行時メソッドでさえ、誰かが ARM ターゲットをサポートする優れたライブラリを指し示すことができれば受け入れられます。