What does _imp_ mean?

Someone here just asked this question to one of our internal mailing lists:

I think this is a rather basic question, but I can’t find an answer in any debugging books I have or on the Net with google.

How does “_imp” get added to function names and what does it mean? Often when I am debug in ntsd I jump into functions named _imp_XXX. I’m curious what this decoration means? Is it related to functions exported from a DLL?

 

It's actually a good question, the answer has to do with how DLL's work under the covers.

When you reference a function located in a DLL, the compiler just inserts:

    call CreateFile

into your source code.

When you link your module with the library, the librarian creates a "thunk" for that function that looks like:

    jmp [_imp__CreateFile]

It also defines a global variable named "_imp__CreateFile",  in your data section.  It also inserts a DLL import reference in your binary that contains the name of the external reference (the DLL name and the entrypoint in that DLL).  That import reference also contains the location of that global variable (table that contains the global variable's called the "Import Address Table", or IAT).  When the loader fixes up your module, the loader will insert the address function referenced by the import reference (CreateFile in this case) into that global variable.

This way, the loader only needs to fix up one location in memory for each DLL import, not every single possible occurrence, which can be a HUGE performance win when loading the module.

The interesting thing about this is that the call into the thunk is actually unnecessary.  The compiler could just as easily have inserted:

    call [_imp__CreateFile]

when it generated the code.  But there's one small problem - the compiler has no way of knowing if the function you're calling is located in a DLL or in another source file.  Since it can't know the difference, it assumes that the code's in another source file, and thus doesn't call into the function pointer.

Fortunately, there IS a solution.  The compiler defines a declaration specifier called "__declspec(dllimport)" that informs the compiler that the function in question will be located in a DLL.  In that case, it uses the latter form of the CALL instruction instead of calling into the thunk.

This can be a huge improvement in performance because removing the thunk improves level2 cache locality.

So if you see the call [_imp_<function>] pattern, you know that the DLL used __declspec(dllimport).

And if you see a call into your DLL that's going through the thunk, you should seriously consider using __declspec(dllimport) to improve your performance.