Use case of dllimport in VisualStudio

c++, linker, visual-c++

Solution

Raymond Chen describes the dll import mechanism in detail in this series; summing it up, `dllimport` for functions is essentially a performance optimization.

If you don't mark a function as `dllimport` the compiler and the linker will treat it as a normal function, with "static" function calls resolving it to the stub found in the import library. The stub actually has to fetch the address of the imported function from the IAT and perform a `jmp` there (i.e. it has to somehow convert the direct call that the compiler generated to an indirect call), so there's some performance penalty in this two-step process.

`dllimport`, instead, tells the compiler that it has to generate code for an indirect call via the IAT right from the compilation phase. This reduces the indirections and allows the compiler to cache (locally to the function) the target function address.

Notice that, as MSDN says, you can omit `dllimport` only for functions; for data it's always necessary, because there's not a mechanism available for the linker to rework the direct accesses to variables generated by the compiler in indirect ones.

(all this was particularly relevant in times of "classical" linkers; nowadays, with link-time code generation enabled, all these points can be worked around by simply letting the linker fully generate the function calls/data accesses)

Problem

I always wondered what is the real use case of `__declspec(dllimport)`. I know that building a shared library requires to export its symbols using `__declspec(dllexport)` and then the user of the library use theses symbols as `__declspec(dllimport)`. Then, you should build your shared library with a special define which enables `dllexport` and if the flag is not set, the symbols are defined as `dllimport`. However, I never used `dllimport` at all and it just works. I have two projects: ImportExport Has a small Util class which is build with EXPORTING defined Util.h: ``` #ifndef _UTIL_H_ #define _UTIL_H_ #if defined(EXPORTING) # define EXPORT __declspec(dllexport) #else # define EXPORT // I should use __declspec(dllimport) but client will try out #endif class EXPORT Util { public: static void test(); }; #endif // !_UTIL_H_ ``` Then in the source file Util.cpp: ``` #include <iostream> #include "Util.h" void Util::test() { std::cout << "Testing..." << std::endl; } ``` Nothing much complicated, as you can see, when the user will use this file, EXPORT will not be defined at all (where it should be defined to dllimport). The client exe Main.cpp: ``` #include <Util.h> int main(void) { Util::test(); return 0; } ``` Links to ImportExport.lib without any define set, just works. No undefined reference. I wonder why is the use case of dllimport? Is it present for backward compatibility? Note: All the code presented was tested on VisualStudio 2012 Express.

Original source