cvisual-c++

Calling Convention Name Mangling in C


What I ask is NOT how to disable C++ name mangling (i know its extern "c"). The question is not about C++

As far as i know, when i declare a function as __stdcall its name should be mangled like in _FuncName@8 (for two int parameters). When I declare a function as __cdecl it should be mangled like in _FuncName.

Sounds fine but is it really like this?

There are two cases that I don't understand:

1-) I'm making a dll in vc++2013 and I use __declspec(dllexport) on a __cdecl function. its exported without any underscore (just FuncName). I don't have a .def file or anything and not using pragma export.

2-) Most of Windows API functions are __stdcall. But they don't have _ or @. For example they are exported like MessageBoxA without any mangling.

So how can this be explained?


Solution

  • Yes, Visual C++ adds name decoration to C symbol exports, as well as name mangling of C++ exports. You can read up on the name decoration conventions on MSDN in the topics for each calling convention keyword. The extern "C" linkage specification actually switches the exported symbols from C++ name mangling to C name decoration, which surprises people from time to time.

    So in the case of a C file that exports a function, if you read the documentation on MSDN for __cdecl very, very closely, you'll see that it mentions that the "Underscore character (_) is prefixed to names, except when __cdecl functions that use C linkage are exported." This still isn't as clear as it could be, since "exported" here refers to DLL export, and it also applies to non-function symbols such as exported data. This is what you're seeing in your own code.

    My speculation is that these names are undecorated for DLL export in order to make language interop easy. You'll note that the linkage symbol name exports still have the leading underscore, which you can see if you dump the exports of the .lib file.

    As for the second case, the __stdcall Windows API functions are exported with specific names using .def files. That's how you get the default name mapped to the narrow- and wide-character versions of the APIs, too. You can get the same effect with #pragma comment(linker, "/export:alias=_original"), but it's probably most portable to use the .def file approach.

    You can find a story about The history of calling conventions on Raymond Chen's The Old New Thing blog.