Search code examples
c++g++ld

Is it possible to wrap a member function of a C++ class?


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?


Solution

  • 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.