[M3devel] __declspec(dllimport)?

Tony Hosking hosking at cs.purdue.edu
Mon Feb 11 17:23:47 CET 2008


Do we know that this actually results in any real performance  
improvement.

On Feb 11, 2008, at 5:34 AM, Jay wrote:

> __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. Get it now!




More information about the M3devel mailing list