How do import libraries work and why doesn't M

2019-04-06 08:02发布

问题:

I looked at this page: An In-Depth Look into the Win32 Portable Executable File Format

It explains that the linker needs an import library because the compiler can't distinguish between normal function calls and API-function calls. But they say also that __declspec(dllimport) specifies a function call to be an API-Call so the linker links against __imp_[function-name]. But with this keyword the compiler should know that this is a call to an API-Function.

Why does the linker still need an import library? The compiler could mark this symbol as imported by prepending __imp_ to the function name and could make a call to a function pointer (which is an unresolved symbol yet) and the linker could replace this symbol (because it sees that this an API call) with the IAT entry's address.

And why can the MinGW-linker use "MinGW-DLLs" directly but the Visual-Studio linker needs an import library?

As I read the post some other questions were also raised. How does the "dlltool (or linker)" (whichever creates the import library) know the location of an IAT entry before linkage with the final executable has been done? I thought the IAT entries would be constructed at link-time with the final executable. The post said, that every API-Call has a fixed position in the IAT table, never-mind how many DLLs will be linked. I cannot imagine how that could be achieved.

回答1:

It is possible to link to DLL without an import library as MinGW clearly demonstrates. Hence the question is why MSVC decided to omit this feature.

The reasons are primarily historic.

Back then in 1983 when Windows came around and DLLs were designed there were many toolchains (compilers, linkers) from different vendors. Going out asking the vendors to implement support for linking "DLLs" for a minority OS was clearly not an option.

So they made a decision to write a tool to generate a library everyone and their dog could link against even if a linker had absolutely no idea about DLLs.

Besides import libraries offer some features that were vital 3 decades ago but are next to obsolete now. First is the ability to import a symbol by ordinal — i.e. DLL has an option to offer no names at all only a list of addresses; the ordinal is an index in this list. Made sence when the amount of RAM was severely limited.

Second is the support for different name mangling schemes. Even in C there is a name mangling scheme, for instance FooBar may become _FooBar@4 (it depends on the platform and the calling convention). It made perfect sense for a DLL to export "FooBar" on every supported platform for consistency (and it makes the life of GetProcAddress() user easier). Import library implements the mapping from _FooBar@4 to FooBar.

This is based on the blog (1, 2) of Raimond Chen, the man who was involved in Windows development from the very beginning.