0

I'm trying to wrap a member function of a C++ class. I've successfully wrapped system functions such as fstat, so the GNU linker, ld, creates a reference to __wrap_fstat and the real fstat is called by __real_fstat, but I can't seem to wrap a class member function. Here's a simple example of a class. I'd like to wrap test().

Foo.hpp

class Foo
{
public:
    Foo() {};
    ~Foo() {};
    void test();
}

Foo.cpp

#include "Foo.hpp"

void Foo::test()
{
    printf("test\n");
}

I've tried this

g++ -o foo Foo.o -Wl,--wrap=Foo::test

The linker doesn't produce an error, but test() isn't wrapped. Does anyone know how to wrap a C++ class member function?

Epsilon
  • 1,016
  • 1
  • 6
  • 15
  • 2
    I guess you have to provide the mangled function name to the link command. – prapin Dec 26 '21 at 09:00
  • Does this answer your question? [How to wrap functions with the \`--wrap\` option correctly?](https://stackoverflow.com/questions/46444052/how-to-wrap-functions-with-the-wrap-option-correctly) – Klaus Dec 26 '21 at 09:05
  • @Klaus I know how to wrap non-member functions. I'm trying to wrap a class member function. – Epsilon Dec 26 '21 at 10:07
  • @Epsilon C++ has something called *function overloading* that does not exist in C. So your example using `fstat` doesn't apply, since it is a C runtime function, not a C++ function, thus overloading doesn't exist. – PaulMcKenzie Dec 26 '21 at 14:31

1 Answers1

2

In C++, all symbols names got mangled to ensure uniqueness of the symbol names, when function names are overloaded, placed in classes or subclasses, inside namespaces, etc.

The linker has no knowledge of the C++ original symbol names and only handles mangled symbol names. So to wrap a C++ member function, you have to wrap the mangled function name.

Foo.hpp

class Foo
{
public:
    Foo() {};
    ~Foo() {};
    void test();
};

Foo.cpp

#include "Foo.hpp"
#include <cstdio>

void Foo::test()
{
   printf("Original Foo:test(): this = %p\n", (void*)this);
}

main.cpp

#include "Foo.hpp"
#include <cstdio>

extern "C" void __real__ZN3Foo4testEv(Foo* This);

extern "C" void __wrap__ZN3Foo4testEv(Foo* This)
{
    printf("Wrapped Foo:test(): this = %p\n", (void*)This);
    __real__ZN3Foo4testEv(This);
}

int main()
{
    Foo foo;
    printf("Address of foo: %p\n", (void*)&foo);
    foo.test();
}

Usage:

$ g++ -o foo main.cpp Foo.cpp -Wl,--wrap=_ZN3Foo4testEv; ./foo
Address of foo: 0xffffcc2f
Wrapped Foo:test(): this = 0xffffcc2f
Original Foo:test(): this = 0xffffcc2f

Note the signature of the wrapping function __wrap__ZN3Foo4testEv: it needs to be declared extern "C" to avoid itself to being mangled. And it has access to the this as the first implicit argument. If you need to call the original function, the same apply for the declaration of the real function __real__ZN3Foo4testEv.

To find out the mangled name of a C++ function, there are several ways. One would consist of first building the project without wrapping, and creating a map file from the linker. In the map file, you should be able to find out the mangled name of the desired function.

prapin
  • 6,395
  • 5
  • 26
  • 44
  • When I call test() from main(), it calls the wrapped function as expected. However, if I call test() from another member functions (of Foo), it calls the real version instead of the wrapped function. Do you know why? – Epsilon Dec 29 '21 at 02:02
  • 1
    @Epsilon I guess that the compiler has inlined the call to `test` when you tried from the same class. It doesn't matter whether it is in the same class or not, but it can matter if called from the same *source file* (compilation unit). To be sure, you should put the implementation of `Foo::test()` in its own source file. – prapin Dec 29 '21 at 08:40