Override a function call in C from the same compilation unit

Viewed 6212

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:

  1. Based on hroptatyr's response, adding void get_resolution() __attribute__((weak)); solves the problem when using mingw-gcc but not in my target platform QNX/ARM/gcc(4.4.2)
  2. Even a run time method like function hook is acceptable if someone can point to a good library with support to ARM target.
6 Answers
Related