6

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.
Community
  • 1
  • 1
vijairaj
  • 310
  • 3
  • 10

6 Answers6

5

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.

hroptatyr
  • 4,702
  • 1
  • 35
  • 38
  • The problem is actually in display.c -> How do I force display() to call __wrap_get_resolution() ? – vijairaj Aug 01 '12 at 12:11
  • oh I see, i may have misread the question then. I take it you can't (or don't want to) change display.c at all? – hroptatyr Aug 01 '12 at 12:16
  • 1
    pity, otherwise the `weak` attribute (paired with `alias` maybe) could helped: http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html – hroptatyr Aug 01 '12 at 12:20
  • Though this doesn't solve the problem for my target platform QNX/ARM/gcc, your suggestion of weak attribute works in mingw-gcc. Some more analysis revealed that the effect can be achieved by simply adding the prototype `void get_resolution() __attribute__((weak));` in display.c - This can be achieved without changing the display.c by adding the prototype in a header and passing it as argument to the compiler. – vijairaj Aug 02 '12 at 06:08
  • If you can't modify `display.c`, create a new file `wrapdisplay.c` that contains `#include "intercept.h"` and `#include "display.c"` and compile and link with that instead of `display.c`. – Jonathan Leffler Aug 02 '12 at 06:45
0

An answer is maybe provided here: Override a function call in C

If you want to override a function from a library you can user (unser linux) LD_PRELOAD.

Hope this help.

Regards.

Community
  • 1
  • 1
TOC
  • 4,326
  • 18
  • 21
  • Nope. This question is actually based on and is a special case of [Override a function call in C](http://stackoverflow.com/questions/617554/override-a-function-call-in-c) – vijairaj Aug 01 '12 at 12:05
0

what if you do it this way:

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

N4553R
  • 188
  • 4
  • if `gcc -Wl,--wrap,get_resolution display.c test.c` is the same as `gcc -Wl,--wrap,get_resolution test.c display.c` so. – N4553R Aug 01 '12 at 12:59
  • I failed to notice that you have changed the order. But even after changing the order the behaviour doesn't change. – vijairaj Aug 01 '12 at 13:57
0

The assembler will always call symbols directly if they are defined in the assembly file; there is no way to change this with GNU as (as far as I'm aware). This is assuming that the compiler hasn't already decided to inline the function call!

The solution is to cause get_resolution to be undefined within display.c. To do this I'd recommend splitting it into 2 files, one with get_resolution and one with the rest of the source file. You can do this without actually splitting the file, by putting in #ifdef blocks and compiling it twice with different defines.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
0

I think it is hardly to implement except using shell code.You can see this for the reason.

The author gave us a example of C++ code, and I tried it on your question with similar method, and I failed to achieve your want.So I think the only way to solve it may be use shell code, but ASLR of linux makes it hard.That is all my known, hoping it may help you

Community
  • 1
  • 1
MYMNeo
  • 818
  • 5
  • 9
0

The 'wrap' function performed by gcc is done at the linker stage rather than by the compiler. the compiler knows where get_resolution is because it's in the same compilation unit, so doesn't need the linker to resolve it (which is where the magic happens).

I can't see you can solve this without changing display.c (or one of it's included header files) in some way. Easiest would be to put get_resolution into it's own C source file, separate to display.c.

Roddy
  • 66,617
  • 42
  • 165
  • 277