Search code examples
c++function-callname-mangling

Is it possible to explicitly call a name mangled function?


Suppose I have something along the lines of

struct Foo {
    void goo() {printf("Test");}
}

external void _ZN3Foo3gooEv(Foo *f);

int main() {
        Foo f;
        _ZN3Foo3gooEv(&f);
}

Is it possible to call Foo::goo() through the name mangled version of the function here?

Edit:

As a clarification, this is just an experiment to see if it's possible to explicitly call a name mangled function. There is no further goal here.

I was thought that all member functions basically take the this pointer as their first argument.

I get that this won't link, but I don't get why. I thought that name mangling happens at compile time, and when the linker runs it resolves the calls to the name mangled function. (That's why I figured if we leave _ZN3Foo3gooEv as extern, it would go to the symbol table to look it up).

Am I misunderstanding something here?


Solution

  • You can, with some caveats.

    You either have to use the member function in a way that code will be generated or have it be not inline, and your mangled definition should be extern "C" to prevent "double mangling". E.g.:

    #include <cstdio>
    
    struct Foo {
        const char* message;
        void goo();
    };
    
    void Foo::goo() {
        std::printf("%s", this->message);
    }
    
    extern "C" void _ZN3Foo3gooEv(Foo *f);
    
    int main() {
            Foo f{ "Test" };
            _ZN3Foo3gooEv(&f);
    }
    

    will work fine and be stable specifically in gcc.

    This works because the calling convention for member functions is equivalent to the default calling convention for free functions on most systems. this is passed to member functions as if it was the first argument, with explicit arguments taking the later arg-passing slots. (Registers and/or stack). I believe that this is true for x86-64, ARM 32-bit and 64-bit at least, and 32-bit x86 other than Windows.

    clang seems to specifically support this use case: It inlines Foo::goo into main when gcc pretends that _ZN3Foo3gooEv and Foo::goo after mangling are two separate entities (and thus can't be substituted and inlined).

    With MSVC, you can do something similar. However, in x86-32 code on windows, the calling convention __thiscall is used where instead of passing the this pointer as the first argument, it is passed in the ECX register with other args on the stack. If cross compiling for x86-32 with clang or gcc, you can use [[gnu::thiscall]] (__attribute__((thiscall))). (fastcall is similar if there's only one arg, but with 2 args would pass the first 2 in registers, not just the first 1).


    But there really should be no reason to do this. It can only be viewed as a compiler extension (Since it uses _Capital symbols), and if you need a way to call these functions from C, use a helper void Foo_goo(struct Foo*) that you define in a C++ translation unit. It can also call private member functions, but you can already do this in a standards-compliant way with template specialisations.