Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to find the C++ mangled name to use in GetProcAddress?

The common "solution" to use GetProcAddress with C++ is "extern "C", but that breaks overloading. Name mangling allows multiple functions to co-exist, as long as their signature differs. But is there a way to find these mangled names for GetProcAddress?

like image 929
MSalters Avatar asked Apr 15 '13 13:04

MSalters


People also ask

Does C have name mangling?

Since C is a programming language that does not support name function overloading, it does no name mangling.

What is name mangling in C ++?

Name mangling is the encoding of function and variable names into unique names so that linkers can separate common names in the language. Type names may also be mangled. Name mangling is commonly used to facilitate the overloading feature and visibility within different scopes.

What does GetProcAddress() do?

GetProcAddress verifies that the specified ordinal is in the range 1 through the highest ordinal value exported in the . def file. The function then uses the ordinal as an index to read the function's address from a function table.

Is C++ name mangling deterministic?

It isn't specified by the standard, and has certainly changed between versions of the same compiler in my experience, though it has to be deterministic over some fixed set of circumstances, because otherwise there would be no way to link two separately compiled modules.


2 Answers

The VC++ compiler knows its own name mangling scheme, so why not use that? Inside template<typename T> T GetProcAddress(HMODULE h, const char* name), the macro __FUNCDNAME__ contains the mangled name of GetProcAddress. That includes the T part. So, inside GetProcAddress<void(*)(int), we have a substring with the mangled name of void(*)(int). From that, we can trivially derive the mangled name of void foo(int);

This code relies on the VC++ macro __FUNCDNAME__. For MinGW you'd need to base this on __PRETTY_FUNCTION__ instead.

FARPROC GetProcAddress_CppImpl(HMODULE h, const char* name, std::string const& Signature)
{
    // The signature of T appears twice in the signature of T GetProcAddress<T>(HMODULE, const char*) 
    size_t len = Signature.find("@@YA");
    std::string templateParam = Signature.substr(0, len);
    std::string returnType    = Signature.substr(len+4);
    returnType.resize(templateParam.size()); // Strip off our own arguments (HMODULE and const char*)
    assert(templateParam == returnType); 
    // templateParam and returnType are _pointers_ to functions (P6), so adjust to function type (Y)
    std::string funName = "?" + std::string(name) + "@@Y" + templateParam.substr(2);
    return ::GetProcAddress(h, funName.c_str());
}

template <typename T>
T GetProcAddress(HMODULE h, const char* name)
{
    // Get our own signature. We use `const char* name` to keep it simple.
    std::string Signature = __FUNCDNAME__ + 18; // Ignore prefix "??$GetProcAddress@"
    return reinterpret_cast<T>(GetProcAddress_CppImpl(h, name, Signature));
}

// Showing the result

struct Dummy { };

__declspec(dllexport) void foo( const char* s)
{
    std::cout << s;
}

__declspec(dllexport) void foo( int i, Dummy )
{
    std::cout << "Overloaded foo(), got " << i << std::endl;
}

__declspec(dllexport) void foo( std::string const& s )
{
    std::cout << "Overloaded foo(), got " << s << std::endl;
}

__declspec(dllexport) int foo( std::map<std::string, double> volatile& )
{
    std::cout << "Overloaded foo(), complex type\n";
    return 42;
}

int main()
{
    HMODULE h = GetModuleHandleW(0);
    foo("Hello, ");
    auto pFoo1 = GetProcAddress<void (*)( const char*)>(h, "foo");
    // This templated version of GetProcAddress is typesafe: You can't pass 
    // a float to pFoo1. That is a compile-time error.
    pFoo1(" world\n");
    auto pFoo2 = GetProcAddress<void (*)( int, Dummy )>(h, "foo");
    pFoo2(42, Dummy()); // Again, typesafe.
    auto pFoo3 = GetProcAddress<void (*)( std::string const& )>(h, "foo");
    pFoo3("std::string overload\n");
    auto pFoo4 = GetProcAddress<int (*)( std::map<std::string, double> volatile& )>(h, "foo");
    // pFoo4 != NULL, this overload exists.
    auto pFoo5 = GetProcAddress<void (*)( float )>(h, "foo");
    // pFoo5==NULL - no such overload.
}
like image 173
MSalters Avatar answered Sep 21 '22 10:09

MSalters


Use dumpbin /exports 'file.dll' to get the decorated / undecorated name of all the symbols.

like image 30
rodrigo Avatar answered Sep 23 '22 10:09

rodrigo