How to Get Rid of the _Imp_ Prefix in the Linker in Vc++

How can I get rid of the __imp__ prefix in the linker in VC++?

The __imp__ prefix appears whenever you are linking to a DLL. It does not appear when linking to statically linked libraries. Most likely the code is generated to be linked against a DLL import lib, but you have linked it with a static lib instead.

The prefix is added when you mark the imported function with __declspec(dllimport) - make sure your imports are not using this when not linking against a DLL.

Linking error LNK2019 in MSVC, unresolved symbols with __imp__ prefix, but should be from static lib

From what I remember of my Windows days, in MinGW-built DLLs, the __imp__ symbol prefix is used for the trampoline function that calls into the DLL proper. This symbol is then provided by a small static library with the extension .dll.a.

When you include libssh headers, you need to set a #define to indicate that you're expecting to link statically. If you don't, the libssh functions in the header will be declared __declspec(dllimport) and so the __imp__ symbols will be expected at link time.

I had a look at the libssh source and found this at the top of libssh.h:

#ifdef LIBSSH_STATIC
#define LIBSSH_API
#else
#if defined _WIN32 || defined __CYGWIN__
#ifdef LIBSSH_EXPORTS
#ifdef __GNUC__
#define LIBSSH_API __attribute__((dllexport))
#else
#define LIBSSH_API __declspec(dllexport)
#endif
#else
#ifdef __GNUC__
#define LIBSSH_API __attribute__((dllimport))
#else
#define LIBSSH_API __declspec(dllimport)
#endif
#endif
#else
#if __GNUC__ >= 4
#define LIBSSH_API __attribute__((visibility("default")))
#else
#define LIBSSH_API
#endif
#endif
#endif

You need to define LIBSSH_STATIC, either through #define before the #include <libssh.h> line, or as a /D option. Since you're using CMake, you'll probably do this through add_definitions in CMakeLists.txt.

What is the difference between _imp and __imp?

This is fairly straight-forward identifier decoration at work. The imp_ prefix is auto-generated by the compiler, it exports a function pointer that allows optimizing binding to DLL exports. By language rules, the imp_ is prefixed by a leading underscore, required since it lives in the global namespace and is generated by the implementation and doesn't otherwise appear in the source code. So you get _imp_.

Next thing that happens is that the compiler decorates identifiers to allow the linker to catch declaration mis-matches. Pretty important because the compiler cannot diagnose declaration mismatches across modules and diagnosing them yourself at runtime is very painful.

First there's C++ decoration, a very involved scheme that supports function overloads. It generates pretty bizarre looking names, usually including lots of ? and @ characters with extra characters for the argument and return types so that overloads are unambiguous. Then there's decoration for C identifiers, they are based on the calling convention. A cdecl function has a single leading underscore, an stdcall function has a leading underscore and a trailing @n that permits diagnosing argument declaration mismatches before they imbalance the stack. The C decoration is absent in 64-bit code, there is (blessfully) only one calling convention.

So you got the linker error because you forgot to specify C linkage, the linker was asked to match the heavily decorated C++ name with the mildly decorated C name. You then fixed it with extern "C", now you got the single added underscore for cdecl, turning _imp_ into __imp_.

Linker can not find __imp_clock and __imp_time64 when building a sample of GTSAM

__imp_ prefix in unresolved external runtime library symbol from the linked library means the library was built with DLL runtime (/MD in C++ -> Code Generation -> Runtime Library).

If you build the application with static runtime (/MT) the symbols from the DLL runtime will be unresolved. Runtime settings should be the same for all compilation units.

Semantics of __imp_ symbols

Members of kernel32.lib are not normal object files but special placeholders. From the PE/COFF spec:

Traditional import libraries, that is, libraries that describe the
exports from one image for use by another, typically follow the layout
described in section 7, “Archive (Library) File Format.” The primary
difference is that import library members contain pseudo-object files
instead of real ones, in which each member includes the section
contributions that are required to build the import tables that are
described in section 6.4, “The .idata Section.” The linker generates
this archive while building the exporting application.

The section contributions for an import can be inferred from a small set of information. The linker can either generate the complete,
verbose information into the import library for each member at the
time of the library’s creation or write only the canonical information
to the library and let the application that later uses it generate the
necessary data on the fly.

[...] a short import library is written as follows:

  Archive member header   
Import header
Null-terminated import name string
Null-terminated DLL name string

This is sufficient information to accurately reconstruct the entire contents of the member at the time of its use.

In kernel32.lib on my machine, __imp_ExitProcess is mentioned in the first and second linker members (symbol list) and point to the specific pseudo-object describing the import:

Archive member name at 8: /               
50107C36 time/date Thu Jul 26 01:07:34 2012
uid
gid
0 mode
106CA size
correct header end

2515 public symbols

[...]

3C874 ExitProcess
3C874 __imp_ExitProcess

[...]

Archive member name at 3C874: KERNEL32.dll/
50107639 time/date Thu Jul 26 00:42:01 2012
uid
gid
0 mode
2D size
correct header end

Version : 0
Machine : 8664 (x64)
TimeDateStamp: 50107639 Thu Jul 26 00:42:01 2012
SizeOfData : 00000019
DLL name : KERNEL32.dll
Symbol name : ExitProcess
Type : code
Name type : name
Hint : 371
Name : ExitProcess

So, as you can see, the data in .lib explicitly says that it refers to an import name ExitProcess from the DLL KERNEL32.dll. The linker can use this to build necessary metadata in the import section.

Now, the above only discussed how the __imp_ExitProcess symbol is resolved. I'm not 100% sure but I think if a symbol (e.g. ExitProcess) has been resolved to such an import stub, and it does not start with __imp_, then the linker has to generate a jump stub (for code symbols), or an indirect access (for data accesses) to the IAT slot.



Related Topics



Leave a reply



Submit