Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DLL using __stdcall without name decoration: why does it even work?

Tags:

c

dll

linker

winapi

If I declare a function like this:

#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif

TESTAPI int __stdcall myadd(int a, int b);

The symbol in the DLL is _myadd@8, which makes perfect sense to me (after few hours of reading other questions here, that is).

But the windows libraries seem to do something different. They also use __stdcall (disguised as WINAPI), but the symbols in the DLLs have no name decoration. If the method above where in the windows libs, the symbol would be myadd.

My guess is that they use a def file to alias the symbols. But why does my linker know this when I link to one of these DLLs?

The windows header files declare these functions with WINAPI, so if I call them, the linker should look for the decorated name, as it is a __stdcall function. Yet somehow the linker knows to drop the name decoration.

I've tried to replicate this by writing a small DLL and removing the name decoration with a def file. As expected I get linker errors as the linker is still looking for the decorated name. I've done this in pure C, to make sure that c++ name mangling does not effect it.

edit: to clarify, MSVC 14.0 / VS2015, 32-bit

like image 559
Stefan Avatar asked Aug 02 '16 00:08

Stefan


1 Answers

There is some barely documented magic at work here. Lets look some WIN32 API function, like RegQueryValueExW. It is defined in the winreg.h file like this:

WINADVAPI LSTATUS APIENTRY RegQueryValueExW(...);

Where WIADVAPI is a __declspec(dllimport) and APIENTRY is a moniker for the __stdcall naming convention. Also note, that all functions in the header are declared as extern "C". So by all means, this function should use name decoration, and its DLL export should be _RegQueryValueExW@24. Yet when we are looking advapi32.dll exports using dumpbin /exports command, we see an undecorated name:

advapi exports

Now lets closely examine advapi32.lib file using dumpbin /headers advapi32.lib command:

enter image description here

Note the undecorate specifier, that allows to link decorated name to the undecorated export. You could achieve the same result for your dll using a def file with EXPORTS section containing undecorated names. See this article and this answer for the additional information.

Also, everything written above is valid only for the x86 applications. C functions in the x64 bit environment are linked without name decoration:

The form of decoration for a C function depends on the calling convention used in its declaration, as shown in the following table. This is also the decoration format that is used when C++ code is declared to have extern "C" linkage. The default calling convention is __cdecl. Note that in a 64-bit environment, functions are not decorated.

like image 139
Ari0nhh Avatar answered Nov 07 '22 22:11

Ari0nhh