问题
Can you help me to understand, why do we need .lib files when importing functions and data from dll?
I've heard, that it contains a list of the exported functions and data elements from the corresponding dll, but when I used CFF Explorer to explore my dll, I found out that dll already has addresses of exporting functions so I theoretically can link my program with .dll without any additional files.
Can you, please, explain what kind of data is stored in the .lib files more detailed.
And, also, yes, I know, that visual studio forces us to add .lib files into additional dependencies section, but why does it really needs them?
回答1:
When your source code statically calls exported DLL functions, or statically accesses exported DLL variables, those references are compiled into your executable's intermediate object files as pointers, whose values get populated at run-time.
When the linker is combining the compiler-generated object files to make the final executable, it has to figure out what all of the compiler-generated references actually refer to. If it can't match a given reference to some piece of code in your executable, it needs to match it to an external DLL instead. So it needs to know which DLLs to even look at, and how those DLLs export things. A DLL may export a given function/variable by name OR by ordinal number, so the linker needs a way to map the identifiers used by your code references to specific entries in the EXPORTS
tables of specific .dll
files (especially in the case where things are exported by ordinals). Static-link .lib
files provide the linker with that mapping information (ie FunctionA
maps to Ordinal 123
in DLL XYZ.dll
, FunctionB
maps to name _FunctionB@4
in DLL ABC.dll
, etc).
The linker can then populate the IMPORTS
table of your executable with information about the appropriate EXPORTS
entries needed, and then make the DLL references in your code point to the correct IMPORTS
entries (if the linker can't resolve a compiler-generate reference to a piece of code in your executable, or to a specific DLL export, it aborts with an "unresolved external" error).
Then, when your executable is loaded at run-time, the OS Loader looks at the IMPORTS
table to know which DLL exports are needed, so it can then load the appropriate DLLs into memory and update the entries in the IMPORTS
table with real memory addresses that are based on each DLL's EXPORTS
table (if a referenced DLL fails to load, or if a referenced export fails to be found, the OS Loader aborts loading your executable). That way, when your code calls DLL functions or accesses DLL variables, those accesses go to the right places.
Things are very different if your source code dynamically accesses DLL functions/variables via explicit calls to GetProcAddress()
at run-time. In that case, static-link .lib
files are not needed for those accesses, since your own code is handling the loading of DLLs into memory and locating the exports that it wants to use.
However, there is a 3rd option that blends the above scenarios together: you can write your code to access the DLL functions/variables statically but use your linker's delay-load feature (if it has one). In that case, you still need static-link .lib
files for each delay-loaded DLL you access, but the linker populates a separate DELAYLOAD
table in your executable with references to the DLL exports, instead of populating the IMPORTS
table. It points the compiler-generated DLL references to stubs in your compiler's RTL that will replace the references with addresses from GetProcAddress()
when the stubs are accessed for the first time at run-time, thus avoiding the need for the references to be populated by the OS Loader at load-time. This allows your executable to run normally even if the DLL exports are not present at load-time, and may not even need to load the DLLs at all if they are never used (of course, if your executable does try to access a DLL export dynamically and it fails to load, your code is likely to crash, but that is a separate issue).
回答2:
I've heard, that it contains a list of the exported functions and data elements from the corresponding dll, but when I used CFF Explorer to explore my dll, I found out that dll already has addresses of exporting functions so I theoretically can link my program with .dll without any additional files.
As a trivial example of why this can't always work, consider an executable that accesses two DLLs, one for a Winsock filter and the other for an allocator. And say that on this particular machine, the Winsock filter DLL happens to also implement an allocator with the same API and the allocator DLL happens to also implement a Winsock filter with the same API. How could the compiler know which API functions to access from which DLL? The library file contains the intent in accessing the DLL, that is, the API and functions you want to access.
Importantly, there is no such thing as "The corresponding DLL". There might be different DLL files on different systems. What the linker needs to know is what the DLL is supposed to look like that it can rely on, not what the DLL that you might happen to use on some particular system might happen to be.
For example, suppose the DLL file contains an allocator. You might have one DLL file for an allocator with debugging, one for an allocator with optimizations for specific CPU versions, and one for an allocator that uses a new, experimental algorithm. What the linker needs to know is the API that all these DLL files implement, not the specific implementation in any one file.
You can produce a LIB file from a DLL file but you might wind up building an executable that doesn't work when using some other version of the DLL file. You would have to assume that whatever this particular DLL happens to do is precisely what every other DLL that implements the same API will happen to do.
来源:https://stackoverflow.com/questions/56085753/why-do-we-need-lib-file-in-case-of-importing-functions-from-dll