I am trying to Override a function call in C, but I am facing a problem when the function is used in the same compilation unit. In the code below, I am trying to replace the function get_resolution(), but I am able to achieve it only if done in test.c but not from 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
My requirement is that, when I call display() from main(), I want __wrap_get_resolution() to be execute but I always see that the original get_resolution() is being called. A little analysis of the dis-assembly reveals that the function get_resolution is called differently:
In display() -> The address of get_resolution() is already resolved
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
In main() -> The address of get_resolution is not yet resolved
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
The question now is, how to prevent the compiler from resolving the address of get_resolution() used in the function display() and instead use the relocation table, so that the get_resolution() function can be overridden during the linking stage?
EDIT:
void get_resolution() __attribute__((weak));
solves the problem when using mingw-gcc but not in my target platform QNX/ARM/gcc(4.4.2)Compile and link the file with your reimplementation ( override. c ). This allows you to override a single function from any source file, without having to modify the code. The downside is that you must use a separate header file for each file you want to override.
When the base class and derived class have member functions with exactly the same name, same return-type, and same arguments list, then it is said to be function overriding.
Just use the preprocessor for that:
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();
...
}
The idea is to "rename" function calls to your wrapper functions after you put all the code that needs to see the original functions.
A dirtier version could be to shadow the function address locally, like so:
int main()
{
void(*get_resolution)() = __wrap_get_resolution;
get_resolution();
...
}
This one would work but could give you some nasty warnings.
Edit
Even though pointed out in the comments that changing display.c
is not desired, here the weak
attribute solution, from 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();
}
and from now on, wherever you call get_resolution()
(and have the "strong" version compiled in) the wrapped version gets called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With