How to disable C++ 7.1 Name mangling? :( - c++

I have a library code which is written in VS 2003 , C++ 7.1
I managed to compile it in VS 2010. Now i need to compile it in VS2003 as well.
Problem is that i can not prevent VS2003 name mangling !
I used __declspec(dllexport) __stdcall before function name and i also put codes in extern "C" block.
I still get mangled function names when i compile it in VS 20003. I dont need a .def file when i use __declspec(dllexport) right?
hee is the code :
extern "C"
{
void __declspec(dllexport) __stdcall FreeMyObject(MyObjectHandle pObj)
{
delete pObj;
}
}
Also "Callin Convention" is __cdecl (/Gd)
Why i get mangled function names? is there any options i need to set in compiler option?

The keyword _stdcall, along with _cdecl, _thiscall, and others, are all calling conventions specifying how the compiler handles pushing and popping the arguments and the return value. Functions names made with _stdcall (at least in visual studio) are "decorated" when they are exported. If you want to find the exported name of the function, you can use the visual studio command line function DUMPBIN /EXPORTS "DLL file location". Your function name will probably look something like this: _FreeMyObject#(some number). You could also use a .def file and define the name yourself, but I personally think that is a pain.

Related

Wrong 32-bit calling convention for InterlockedExchange for Clang++, but MSVC is fine

I am using clang power tools to compile a project which is usually compiled using visual studio.
In boost's lwm_win32.hpp header (yes we are using an old version of boost and currently cannot update) I get an error reading.
function declared stdcall here was previously declared without calling convention
the line in question is:
extern "C" __declspec(dllimport) long __stdcall InterlockedExchange(long volatile *, long);
I don't get any errors or warnings for this line when compiling with visual studio. Interestingly I don't get any even if I manually change the calling convention from __stdcall to __cdecl.
Clang tells me which previous declaration it has seen. By manually inspecting this location I would say clang is right. After deciphering all preprocessor defines I would also say __cdecl is what should be seen by visual studio. However, neither the official documentation for InterlockedExchange, nor the official documentation for the intrinsic do mention a specific calling convention.
So basically I am unsure what the root of the problem is. Visual studio accepting any calling convention in the declaration? Clang not seeing the correct declaration due to some preprocessor macros set to the wrong value? Boost declaring the wrong calling convention? I must admit I am confused.
Visual Studio version is 2015 Update 3.
Clang++ version is 6.0.0 called with parameter -fms-compatibility-version=19.
EDIT
As suggested in the comments I had a look at the preprocessor output of MSVC and Clang. They looked rather identical to me. For both the line from boost expands to
extern "C" __declspec(dllimport) long __stdcall _InterlockedExchange(long volatile *, long);
Both have
#pragma intrinsic(_InterlockedExchange)
and the declarations
long __cdecl _InterlockedExchange(long volatile * _Target, long _Value);
LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
as well as several inline implementations for different overloads.
In both compilers I target 32-bit (-m32 for clang).
Do the clang power tools offer you things that you really don't want to live without?
If not (and I imagine that is a big if) then you might consider experimenting with VS 2017's support for clang. I have no experience of it personally and it's all still a bit new but what I do know is that MS are putting a lot of work in and it may well pay off in the long run.
As it is, I think you might be out on a bit of a limb. And whatever should and should not be in the header files, I would say that what MS say goes, wouldn't you?
Why are you stuck with that old version of boost? That might be a blocking issue here.

Using a .def in Visual Studio instead of dllimport/dllexport with global variables

In the PluginLoader.exe's main.cpp:
int Lives = 9;
The project also contains a .def file that exports the Lives variable (mangled C++):
EXPORTS
?Lives##3HA
Using dependency walker, I verified when opening PluginLoader.exe that ?Lives##3HA is indeed being exported. A .lib is also being exported which should contain the stubs that we can link against in other projects. Using dumpbin.exe on the stub PluginLoader.lib I get:
4 ?Lives##3HA
1 __IMPORT_DESCRIPTOR_PluginLoader
2 __NULL_IMPORT_DESCRIPTOR
4 __imp_?Lives##3HA
3 ⌂PluginLoader_NULL_THUNK_DATA
PluginLoader is loading a SimplePlugin.dll using LoadLibrary / GetProcAddress. SimplePlugin.dll has a main.cpp that looks like this:
extern int Lives;
extern "C" __declspec(dllexport) void PluginMain()
{
++Lives;
}
SimplePlugin also links against the stub PluginLoader.lib. When trying to increment Lives, I always crash with an ACCESS VIOLATION. It would appear that my SimplePlugin.dll is pseudo getting its own version of the Lives variable, even though it linked against the stub.
If I change ONLY the SimplePlugin's Lives to:
__declspec(dllimport) extern int Lives;
Everything works as expected. Why is this? I thought the purpose of a .def was to not have to use dllexport/dllimport. My current hypothesis is that dllimport with a global variable is doing some trickery behind the scenes (how does &Lives work in the dll vs the exe?). Does this have something to do with the __imp_?Lives##3HA?
Note: Importing function pointers without dllimport works just fine. Its only with global variables that I get a crash. This reproduces in VS 2010 and 2012
Sample project: https://db.tt/maV0oWop
Compiler indeed generates indirection code when you use dllimport on data.
The reason is that a DLL can only export a pointer to the exported data and dllimport does the magic of dereferencing that pointer for you. That obviously is not required for function pointers.
MS docs on that

fatal error LNK1127: library is corrupt --> after adding extern "C" to function prototype

I have an external library made using C code. I wish to call a function from the library in my c++ project. The original format of the function prototype was.
extern void butterThreeBp(real_T eml_dt, real_T eml_fl, real_T eml_fu, real_T eml_b3[7], real_T eml_a3[7]);
And this caused the following linker error in MSVC2008
error LNK2019: unresolved external symbol "void __cdecl butterThreeBp(double,double,double,double * const,double * const)" (?butterThreeBp##YAXNNNQAN0#Z) referenced in function "public: void __thiscall myThread::setDRNLc(double)" (?setDRNLc#myThread##QAEXN#Z)
I then changed this prototype to
extern "C" void ...
and then get the following error:
\butterThreeBp.lib : fatal error LNK1127: library is corrupt
I have rebuilt the library numerous times and am pretty certain that it is not corrupt. Any help would be great. Thanks!!
You do not have to use the included LCC compiler with MATLAB. The simplest solution is to get MATLAB to use VC++. http://www.mathworks.com/support/compilers/R2010b/index.html
IIRC you should add extern "C" only when compiling with C++ compiler.
Something like that:
#ifdef __cplusplus
extern "C" {
#endif
// the declarations
#ifdef __cplusplus
}
#endif
Got it! I generated the library code using the MATLAB embedded coder and was using Matlab's Lcc built in compiler to build the library. I am working on the main application in MSVC, therefore I guess there must have been some calling convention problem between the library (Lcc) and my main project (MSVC). This problem was particularly difficult to spot because one of my libraries (ButterOneLp) worked fine, even though it was generated using Lcc. However, another library did not work.
The problem was fixed by using the
mex -setup
. . . command in MATLAB and changing the default compiler to MSVC as opposed to the default Lcc.
I think that Lcc is based on gcc, so if anybody knows how to change the calling convention in the C++ code so that gcc/lcc libraries can be called from MSVC, that would be great. However, that is a whole different question to the original on posted.
The moral of this story is to check that your library and calling application are/were built using the same compiler if you get a "fatal error LNK1127: library is corrupt".

Mixed calling conventions make compilation errors

I have a library (C++) which has some API functions. One of them is declared as __cdecl, but gets a function poiner from __stdcall. Something like:
typedef int (__stdcall *Func)(unsigned char* buffer);
//...
int ApiFunc(Func funcPtr); //This is __cdecl since it is an 'extern "C"' library and the calling convention is not specified
Then - I have a C++ executable project which uses this library, but doesn't call the above API or uses the Func type.
After changing the calling convention of Func to __stdcall, I get the following compilation error:
error C2995:
'std::pointer_to_unary_function<_Arg,_Result,_Result(__cdecl *)(_Arg)> std::ptr_fun(_Result (__cdecl *)(_Arg))' : function
template has already been
defined c:\program files\microsoft
visual studio 8\vc\include\functional
Any idea what could it be?
Thanks in advance!!
Err.. they're incompatible. You have to specify the same calling convention on both sides of the call. Otherwise attempting to call will blow up the machine stack.
They ARE compatible, in Windows at least (and in Linux there isn't __stdcall at all...)
The problem was that by mistake, the library re-defined __stdcall for compatibility with Linux, as:
#ifndef __MYLIB_WIN32
//Just an empty define for Linux compilation
#define __stdcall
#endif
The exe project includes this definition, and __MYLIB_WIN32 was not defined in it, but in the library only.
Changing the above definition to:
#ifndef WIN32
//Just an empty define for Linux compilation
#define __stdcall
#endif
and everything works fine.
Thank you all.

How can i avoid name mangling?

How can I avoid name mangling in C++?
You can't. It's built into compilers to allow you overloading functions and to have functions with the same name in different classes and such stuff. But you can write functions that are mangled like C functions. Those can be called from C code. But those can't be overloaded and can't be called by "normal" C++ function pointers:
extern "C" void foo() {
}
The above function will be mangled like C functions for your compiler. That may include no change at all to the name, or some changes like a leading "_" in front of it or so.
Other way:
Controlling Names Used in Assembler Code (gcc spec.)
You can specify the name to be used in the assembler code for a C function or variable by writing the asm (or __asm__) keyword after the declarator. It is up to you to make sure that the assembler names you choose do not conflict with any other assembler symbols, or reference registers.
To specify the assembler name for functions, write a declaration for the function before its definition and put asm there, like this:
int func () asm ("MYFUNC");
int func ()
{
g++ will compile it and nm -D output will be
0000000000001e02 T MYFUNC
instead of
0000000000001e02 T _Z4funcv
Tested on g++ 4.9.2
You mean so you can export your function from a library?
extern "c" { your code here }
Schaub's answer is factually incorrect. The most common reason to avoid name mangling is because you are building a shared library (on Windows, a DLL) that is used by client software you don't control that expects certain exported function names. Because of mangling differences between compilers, such interfaces have historically avoided name mangling.
What you have to do is this. First, in your source code prepend extern "C" to get rid of C++ mangling; this still leaves C mangling though. Second, use the -Wl,--kill-at command line option when compiling.
Example:
extern"C" __declspec(dllexport) hresult __stdcall MyExportedFunction( ... )
{
....
}
And compile with:
gcc -shared -mwindows -Wl,--kill-at -Werror ... -o MyLib.dll MyLib.cpp -lkernel32 -l...
You can verify whether you got it right using Dependency Walker.
If you want to compile to wasm you can add the --demangle option to the wasm-ld linker via clang -Wl,--demangle