Does someone know how to obtain the mangled symbol name based on a given C++ function signature?
e.g.:
__stdcall unsigned char MyClass::MyFunc(const int param1, int param2);
would become:
?MyFunc#MyClass##QGE#?BHH#Z
when using the Microsoft Visual C++ Compiler.
I was thinking about some WINAPI-function, but I did not find any...
EDIT: Ok - I know, this is not a very clearly formulated question. What I want to achieve is the following:
GetMangledName("__stdcall unsigned char MyClass::MyFunc(const int param1, int param2);");
// Returns "?MyFunc#MyClass##QGE#?BHH#Z"
I believe the name mangling is compiler dependent and not part of the c++ specification. So as far as I can see the only reliable way is to invoke the actual compiler that you are using and get back a mapping of how the source names map to the mangled names.
Related
I saw this line of code in a source code and I simply can't understand what its meaning is even after having searched around (I don't know what exactly to search for). Can someone explain what this is for or where I can read up on it?
using f_loadLibraryA = HINSTANCE(WINAPI*)(const char* lpLibFilename);
Sorry for such a dumb question...
f_loadLibraryA becomes a type (almost like a typedef) for a function that takes a const char* as its single parameter and has a return type of HINSTANCE.
WINAPI is a #define macro that maps to a calling convention, which is not part of the C++ standard, but exists to establish how the function should be called (how parameters are loaded onto the call stack, and other low level things like that). It's usually either __stdcall or __cdecl.
It declares f_loadLibraryA to be a type alias for HINSTANCE(WINAPI*)(const char* lpLibFilename).
See also: https://en.cppreference.com/w/cpp/language/type_alias
I am facing linker error for a XERCES function while upgrading it from 2.6 to 2.8
unresolved external symbol (?resolveEntity#HandlerBase#xercesc_2_8##UAEPAVInputSource#2#QBG0#Z)
I checked the xerces-c_2.8.lib and found that name lib is bit different that the one in my .obj file It is as shown
?resolveEntity#HandlerBase#xercesc_2_8##UAEPAVInputSource#2#QB_W0#Z
So I understand that linker wont find the match and throw error.
But I am unable to understand why my .obj file contains different signature.
code is including correct header files and lib from still incorrect name.
Any help would be appreciated.
You can use the undname.exe utility to recover the original C++ declaration.
?resolveEntity#HandlerBase#xercesc_2_8##UAEPAVInputSource#2#QBG0#Z converts to:
virtual class xercesc_2_8::InputSource *
__thiscall xercesc_2_8::HandlerBase::resolveEntity(
unsigned short const * const,
unsigned short const * const)
?resolveEntity#HandlerBase#xercesc_2_8##UAEPAVInputSource#2#QB_W0#Z converts to:
virtual class xercesc_2_8::InputSource *
__thiscall xercesc_2_8::HandlerBase::resolveEntity(
wchar_t const * const,
wchar_t const * const)
Note the differences in the argument types, unsigned short vs wchar_t. For some reason, your compiler is not recognizing the wchar_t type. That could be because you have a very old compiler. Or it can be an option set wrong, on msvc it is C/C++, Language, "Treat wchar_t as Built-in type". Or you've got a macro that hacks the string type to unsigned short.
C++ allows function overloading so the parameters to a function are recorded in the name mangling. you might be trying to call the function with different parameter types than what the DLL expects.
Make sure that your header file matches the version of your DLL.
From the example of hooking C++ methods with MobileSubstrate I found this:
void (*X_ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE) (void* something, void* loader, unsigned long identifier, void* request, const void** response);
Why do we need this x_zn20...23....7...14 etc. between the names? What does this mean? I don't think that this is the real name.
C++ mangles names of symbols emitted to the binary, to distinguish void foo(int) and void foo(double). Also, on many platforms, it needs to encode X::Y somehow to make it an alphanumeric string. This adds the extra characters and is platform dependent.
The notation you see is called name mangling.
It's a way of encoding method signatures (in the binary) so that they are unique across the binary, even if two methods have the same name and they belong to classes of the same name, but differ only by the scope (namespace) or parameters
It looks like some platform specific hack to bind to a symbol in a compiled object.
You should look for the header file which contains that function name and call it properly.
This is bad because as compiler evolve and the code base changes specifics of the symbol name will change.
platform : win32 , language : c++
I get this error when I call an imported function I declared:
Run-Time Check Failure #0 - The value of ESP was not properly saved
across a function call. This is
usually a result of calling a function
declared with one calling convention
with a function pointer declared with
a different calling convention.
And this is the code I used:
int LoadSongFromFile(int module);
typedef int (CALLBACK* loadSongT)(LPCTSTR);
//...
HINSTANCE dllHandle = NULL;
loadSongT loadSongPtr = NULL;
dllHandle = LoadLibrary(L"miniFMOD.dll");
loadSongPtr = (loadSongT)GetProcAddress(dllHandle,"SongLoadFromFile");
int songHandle = loadSongPtr(L"C:\b.xm");
The function I'm trying to call is SongLoadFromFile which requires one argument (in C# it is string so I assume its LPCTSTR in C++) and returns an int value.
Can somebody check what have I done wrong?
P.S. songHandle gets a weird negative value of -858993460
This is how I can call that function from C# :
[DllImport("MiniFMOD.dll")] public static extern int SongLoadFromFile(string name);
P.S. 2 : Using *typedef int (__cdecl loadSongT)(char);* doesn't return an error but songHandle comes up as 0.
miniFMOD.dll is an unmanaged library
I think the other people are misunderstanding the question. It seems to me that minifmod.dll is a native library that exports a function named SongLoadFromFile. The existing code that calls this is managed code (C#) that uses DllImport to call the function in the native DLL. From what little information I could gather by a few Google searches, it looks as though it should be declared as follows:
typedef int (__cdecl * SongLoadFromFileT)(const char*);
Importantly, it is __cdecl calling convention and it takes an ANSI string instead of a Unicode string.
As an aside, I find it strange that I can't find ANYTHING on minifmod.dll other than a few forum posts on a Russian website and some SO questions from this guy. The only "legitimate" information I can find on minifmod is a small static library with similar functionality. I wonder if minifmod.dll is some kind of commercialized version of the static library; at least that would explain why there is not much public documentation about it.
Ah, I found it; it is a Delph port of minifmod (http://www.cobans.net/minifmod.php).
You need to make sure to specify the right calling convention in your function pointer prototype ('CALLBACK' might be the wrong choice).
The calling code uses the calling convention not matching that of the function being called. See this very similar question. You need to open the header defining that function (should come with the library you try to use), look the convention up and change your function pointer declaartion accordingly.
I'm using Visual Studio 2005.
------------------------[ luapassing.cpp ]--------------------
#include "lua.h"
static int myCfunc (Lua_State *L){
double trouble = lua_tonumber(L,1);
lua_pushnumber(L,16.0 -trouble);
return 1;
}
int luaopen_luapassing (Lua_State *L){
static const lua_reg Map [] = {{"dothis",myCfunc},{NULL,NULL}};
luaL_register(L,"cstuff",Map);
return;
}
-------------------------[ csample.lua ]-------------------------
package.cpath = "./CLua2.dll"
require "luapassing"
print("hola")
print(seth.doThis(120))
I see several issues. I'll describe them, and provide a code fragment that should work as I believe you intended this sample to work.
Your first problem is that the C++ compiler mangled the name of the only function exported from your DLL whose name matters to Lua: luaopen_luapassing(). The stock binary distribution for Windows was compiled as a C program, and assumes a C style name for the DLL module entry point.
Also, you have the protocol for the luaopen_x function slightly wrong. The function returns an integer which tells Lua how many items on the top of Lua's stack are return values for use by Lua. The protocol assumed by require would prefer that you leave the new module's table object on the top of the stack and return it to Lua. To do this, the luaopen_x function would ordinarily use luaL_register() as you did, then return 1.
There is also the issue of naming. Modules written in pure Lua have the opportunity to be less aware of their names. But modules written in C have to export a function from the DLL that includes the module name in its name. They also have to provide that module name to luaL_register() so that the right table is created and updated in the global environment. Finally, the client Lua script will see the loaded module in a global table named like the name passed to require, which is also returned from require so that it may be cached in a local in that script.
A couple of other nits with the C code are that the numeric type really should be spelled lua_Number for portability, and that it would be conventional to use luaL_checknumber() rather than lua_tonumber() to enforce the required argument to the function. Personally, I would name the C implementation of a public function with a name related to its name that will be known publicly by Lua, but that is just a matter of taste.
This version of the C side should fix these issues:
#include "lua.h"
static int my_dothis (Lua_State *L){
lua_Number trouble = luaL_checknumber(L,1);
lua_pushnumber(L,16.0 -trouble);
return 1;
}
extern "C" int luaopen_luapassing (Lua_State *L){
static const lua_reg Map [] = {
{"dothis", my_dothis},
{NULL,NULL}
};
luaL_register(L,"luapassing",Map);
return 1;
}
The sample script then needs to refer to the loaded module by its proper name, and to the functions defined by that module by their proper names. Lua is case sensitive, so if the module creates a function named dothis(), then the script must use that same name, and cannot find it named doThis(), for example.
require "luapassing"
print("hola")
print(luapassing.dothis(120))
I should add that I haven't actually compiled and run the above, so there might be a typo or two left as an exercise ;-)
If you're going to be doing a lot of C++ to lua binding, you might want to take a look at luabind.
If you are compiling as C++ and want to match a 'C' interface, you should declare the externally visible functions as extern "C" to avoid name mangling.