[M3devel] __declspec(dllimport)?

Jay jayk123 at hotmail.com
Mon Feb 11 11:34:19 CET 2008


__declspec(dllimport) is a nice little cheap optimization on Windows.
When you are calling a function that you will be dynamically linking to, it saves one instructions per call.
 
On Windows, the way dynamic linking works is that for all your imports, there is one array of pointers in your .dll/.exe.
It could actually be discontiguous. It is an array per .dll rather, with a terminal NULL for each .dll you import from. All the dynamic loader does is write pointers into this array at load time. It does not have to, like, go all through your code patching stuff up.
 
If you just call Foo, but end up importing Foo, the linker generates a one instruction function:
Foo:
   jmp dword ptr[__imp__Foo]
 
__imp__Foo is in that array that gets patched up.
 
However if you declare Foo to be __declspec(dllimport), the compiler will instead of:
  call Foo
generate:
  call dword ptr[__imp__Foo]
 
in fact, if you have multiple nearby calls to Foo, the compiler knows these pointers are "relatively const" and will fetch the pointer and hold it in a register and make the calls through the register.
 
There is a problem with __declspec(dllimport).
Essentially, you know, for every imported function Foo, there is somewhere out there someone implementing it.
They are not importing it. They are exporting it.
While getting this declaration wrong is actually "ok", it ends up costing the implementer an extra instruction on their calls, and generates a linker warning ("importing local function").
 
So what ends up happening usually is either a) the implementer doesn't #include his own header files, generally a bad bad bad idea or b) for every .dll bar.dll, a macro is made up BARAPI and then the code usually goes like:
#ifndef BARAPI
#define BARAPI __declspec(dllimport)
#endif
 
BARAPI void __stdcall Foo(void);
 
and the implementer will define BARAPI to either be nothing/empty, or __declspec(dllexport).
(__declspec(dllexport) is another topic, I'll try not to go into here.)
 
This is a little gross, this proliferation of "cover" macros for __declspec(dllimport).
But it IS a nice little optimization.
Actually I suspect many people think these annotations are required.
But they almost never ever are. But they are nice to have.
 
So, what do people think?
Worth some syntax? In <*extern*> pragmas?
Gcc already understand this stuff I believe.
I think I noticed it when looking at the __stdcall stuff.
 
Another wrinkle here is that Modula-3 has this nice build_standalone() feature, which switches whether or not you dynamically link. It would tend to invalidate statements here, at least about Modula-3 code.
 
On the matter of when __declspec(dllimport) is needed.
 - I'm not sure about C++ classes. You should just never import then really, but use COM instead, but people do.
   (COM is just using pure virtual function calls -- ie: calls through structs containing all function pointers, and get a pointer to said struct via a special C creation function).
 
 - It is needed for data, at least with Microsoft tools. The GNU tools seem to have some workaround here.
 Notice I pointed out the linker generates a function for you if you don't make the annotation. You can't intervene on data accesses with a function call, unless, say, you've inserted a function call for every single data access, or if you can still go back and change the code, like at link time. Data imports are rare and I suggest just never use them. But they are much faster when they suffice, true.
 
__declspec(dllexport) can generally just be replaced with a .def file.
  - again, I don't know about C++ classes 
  - for C++ functions, the .def file will contain some ugly processor-specific mangled names, a little bit difficult/annoying to come up with and put in the .def file, but not impossible by far (link /dump /symbols | findstr /v UNDEF for example) 
  - again, just don't export C++ classes, or mangled/overloaded/etc. names, only export C functions and you are set with a .def file; this also aids compatibility with multiple compilers and languages (!) 
  - (C++ is largely well and good and I can tell you what is good about it, but one thing it is NOT good for is defining dynamically linked interfaces; I think Modula-3 can get into the same trap -- e.g. traffic only in a few base types (integer, text) and opaque types, don't let dynamically linked callers know about your record format/offsets, else you'll have to recompile "too often") 
 
__declspec(dllexport) provides no optimization analogous to __declspec(dllimport).
 
 - Jay
_________________________________________________________________
Connect and share in new ways with Windows Live.
http://www.windowslive.com/share.html?ocid=TXT_TAGHM_Wave2_sharelife_012008
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20080211/87ce8415/attachment-0001.html>


More information about the M3devel mailing list