Date: | July 27, 2006 / year-entry #252 |
Tags: | other |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20060727-00/?p=30343 |
Comments: | 23 |
Summary: | When I wrote that the symbolic name for the imported function table entry for a function is called __imp__FunctionName, the statement was "true enough" for the discussion at hand, but the reality is messier, and the reason for the messy reality is function name decoration. When a naive compiler generates a reference to a function,... |
When I wrote that the symbolic name for the imported function table entry for a function is called When a naive compiler generates a reference to a function, the reference is decorated in a manner consistent with its architecture, language, and calling convention. (Some time ago, I discussed some of the decorations you'll see on x86 systems.) For example, a naive call to the To correspond to the stub function whose real name is The fact that names in import libraries are decorated means that it is doubly crucial that you use the official import library for the DLL you wish to use rather than trying to manufacture one with an import library generation tool. As we noted earlier, the tool won't know whether the ordinal assigned to a named function was by design or merely coincidental. But what's more, the tool won't know what decorations to apply to the function (if the name was exported under an undecorated name). Consequently, your attempts to call the function will fail to link since the decorations will most likely not match up. In that parenthetical, I mentioned exporting under undecorated names. Doesn't that mean that you can also export with a decorated name? Yes you can, but as I described earlier, you probably shouldn't. For as I noted there, if you export a decorated name, then that name cannot be located via Just export those names undecorated. Your future customers will thank you. (Exercise: Why is it okay for the C runtime DLLs to use decorated exports?) |
Comments (23)
Comments are closed. |
Because it most cases, the C Runtime (CRT) is specific to the compiler vendor.
Which is the same reason it was OK for the C runtime to use dllexport, in the “why can’t I GetProcAddress a function that I dllexported?” post, which was linked here under the “you probably shouldn’t” text. ;-)
The name decoration can also change between compiler versions from the same vendor: VC8 had changes compared to VC7.x for example.
Well, for C it’s actually possible to safely link against code built with a different compiler. You don’t have to worry about vtable layout, pointer to member representation, rtti, exceptions, etc., let alone how the other guy decorates his function to include the signature for overloading. For C it’s just the 3 x86 calling conventions, which you basically need anyway to interact with Win32.
For C++, forget it. Exporting undecorated names only solves a part of the problem and will work some of the time but then crash when you least expect it.
Of course for platforms with a sensible ABI this is simpler.
<i>Why is it okay for the C runtime DLLs to use decorated exports?</i>
For _cdecl functions, the decorated names and undecorated names are the same.
How do I export fully undecorated names of c++ methods?
Is it as prone to errors to call a dll function with dynamically binding as with manufacturing an own import library? In both cases the original import library isn’t used.
Because trees look nicer with decorations.
If you’re using LoadLibrary and GetProcAddress with decorated names, you’re in for a world of hurt when the next version of the library is compiled with a different release of the same compiler. If the names are undecorated (and you keep calling conventions, function signatures, etc the same), then you’re limited in certain C++ features you can use, but it will work fine.
The problem with manufacturing an import library isn’t just the name – it’s the mucking around with ordinals that’ll screw you over.
> How do I export fully undecorated names of c++ methods?
With a great deal of pain and suffering. ;)
[Not sure what the ABI has to do with this. […] – Raymond]
The fun with C++ is that a combination of different name mangling algorithms and no standard for the layout of vtables (etc), a class compiled with Visual C++ almost certainly can’t be used directly with code compiled with C++ Builder or GCC. With C, the ABI is specified reasonably well – mostly because it’s a lot simpler – so a DLL compiled with one compiler can generally be used with code compiled in many other compilers, provided this whole name decoration issue is handled correctly.
c++: You don’t. Insted, you go inside an extern "C" block, and write a function which calls your method, and call that from C.
John Andersson: You’ve got to have an agreement between the parties doing dynamic linking that covers the things an import library would tell you, I think.
Why then is it possible at all to export c++ symbols? Can any compiler use them? Is it possible to tell any compiler to “look in this dll for the methods of this class”?
Why is extern C better than def file?
Thursday, July 27, 2006 1:02 PM by josh
> Well, for C it’s actually possible to safely
> link against code built with a different
> compiler.
Only if one of the compiler developers copied the calling convention(s) from the other (or if the two compiler developers cooperated with each other).
> For C it’s just the 3 x86 calling
> conventions, which you basically need anyway
> to interact with Win32.
Mr. Chen already pointed out that applications can define additional calling conventions, and the fact is that compiler developers can too. If compiler developers target Win32 then they have to include Win32 calling conventions among the variations that they support.
The first time I saw "Pascal" as a calling convention in Windows I just figured, great, Windows calling conventions fluctuate according to which Pascal compiler you use this month. Some time later I discovered that Microsoft started calling this __stdcall instead, with the implication that Microsoft actually knew what calling convention they were using and there was some way for callers to find out what to conform to.
Ok, if you have to deal with malicious or insane compiler writers, you can’t safely link any code built with different compilers. They could implement integers with some sort of balanced ternary, and then you’d be totally screwed.
So, to try to sum up a bit… Raymond, you’re basically recommending that everyone should always use __declspec(dllimport), and should use __declspec(dllexport) seldom (only on those routines that are compiler-specific anyway, or on extern "C" cdecl routines), replacing __declspec(dllexport) with .def files in most cases? Is that correct?
Actually Miral, I didn’t see that recommendation at all.
Crikey, this is all newbie stuff, and it hasn’t changed in the last 10 years.
If you make a DLL to be used by other products, yes, you export the symbol as extern "C" and you stay away from C++. Then if the API is properly designed, your DLL can work with all compilers for years to come!
Unless you make a third-party C++ library (ex: MFC, QT) in which case you dllexport the classes, and you will need to keep up with the compiler updates and have different versions of your DLL for different compiler vendors and versions.
If you write .def files instead of using the non-standard keyword __dllexport(), really you need to use the ‘extern "C" because otherwise guessing the decorated name you need to write in the .def file is a huge waste of your time, and it may break in future. In C++, no human should be writing .def files, so that means forget about .def file features like assigning ordinal numbers. You might need to make debug and release versions as well, because c++ could inline a method.
If you make a DLL for your own product’s internal use, none of this matters and you’d just dllexport everything. You’re always compiling/shipping a new version of your DLL with the App anyway. When you use extern "C" on function, you won’t be able to overload them, which can be a pain or a feature.
About ‘pascal’. Pascal was in fashion back in Windows 16-bit and that was the only agreed-upon calling convension. The MacOS API is also all pascal. Pascal was the big thing, not C.
When moving to win32, MS changed to ‘stdcall’ as the agreed-upon calling convention (plus they had the leading compiler at this point). You’ll only see ‘pascal’ in header file that date from the 16-bit days, __pascal has never been implemented, afaik, in a 32-bit C compiler.
Why is it OK for the C Run Time library to use decorated name. That’s obvious! The C Run Time Library is ALREADY compiler-dependant, and therefore doesn’t need to use compiler-independant undecorated names. A new C Run time always come with a new compiler version.
Actually, there are valid and good uses for both exported C++ (member) functions and exporting them only by ordinal.
I inherited a C++ library (compiler-specific, of course) that exported quite a lot of C++ member functions. In fact, it previously had used dllexport on the whole classes. I’m not exaggerating when I say that just the names accouted for over 30% of the DLL.
Applying a bit of carefully designed ordinal ranges, and using the .def file only exporting the symbols by ordinal, this DLL became even lean, and loaded quite a bit quicker.
All it takes is careful ordinal-range reservations, and knowing "This is from now on carved in stone". Actually, as this was C++ it’d have to be considered carved in stone anyway, as one library+dll only fits a specific version from a specific vendor. It’s a bith that one needs to ship 10+ DLL’s, but that’s the way it is without a common C++ ABI.
Friday, July 28, 2006 4:47 PM by Csaba
> The pascal calling convention in 16-bit
> Windows was chosen because of efficiencey,
> not fashion. The callee cleans up the stack
And Ulric said “that was the only agreed-upon calling convension”. That was still miraculous…
> The Intel processors have hardware support
> for this (“RET n” instruction).
And the VAX had an instruction for the caller to get the number of arguments. Other architectures pretty much did not agree in this manner. Pascal was implemented on a lot of architectures (it was in fashion for a while, with good reason).
Some architectures had several implementations made by various parties. In some cases the hardware vendor was also the OS vendor so they specified the calling conventions and there was no question about agreements on those architectures.
The PC didn’t fit that case. If all implementors of Pascal for the PC agreed on a single calling convention, that was miraculous.
The real question is, why don’t we have a GetProcAddress yet which understands name mangling? If I want the C++ function named
int foo(int,int), I just want to call GetProcAddress<int(*)(int,int)>("foo") and have it mangle "foo". Of course, that GetProcAddress would need to be a compiler intrinsic.
It’s just two steps:
1. Mangle the argument (any compiler can)
2. Call real GetProcAddress() (any compiler can)
Michiel: Why? Wouldn’t you rather have a directly-accessible function for mangling (and demangling), rather than burying it inside a GetProcAddress wrapper? (Writing your own wrapper based on the mangler would be trivial; vice-versa is obviously not.)
Also, I’m having a hard time envisioning what you want to use this for that wouldn’t
a. involve building/shipping the DLL and caller together, in which case do you really need GetProcAddress;
b. be better served by giving your overloads different names, probably through extern "C" wrappers, in the first place; or
c. require mangling at runtime.
I found this list of article on Raymond's blog . Raymond's blog is one of the more interesting