[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