問題描述
我知道這對極客來說似乎很基礎.但我想說清楚.
I know this may seem quite basic to geeks. But I want to make it crystal clear.
當我想使用 Win32 DLL 時,通常我只調用像 LoadLibrary() 和 GetProcAdderss() 這樣的 API.但是最近在用DirectX9開發,需要添加d3d9.lib、d3dx9.lib等文件.
When I want to use a Win32 DLL, usually I just call the APIs like LoadLibrary() and GetProcAdderss(). But recently, I am developing with DirectX9, and I need to add d3d9.lib, d3dx9.lib, etc files.
我已經聽夠了 LIB 用于靜態鏈接而 DLL 用于動態鏈接.
I have heard enough that LIB is for static linking and DLL is for dynamic linking.
所以我目前的理解是 LIB 包含方法的實現,并在鏈接時作為最終 EXE 文件的一部分進行靜態鏈接.雖然 DLL 是在運行時動態加載的,而不是最終 EXE 文件的一部分.
So my current understanding is that LIB contains the implementation of the methods and is statically linked at link time as part of the final EXE file. While DLL is dynamic loaded at runtime and is not part of the final EXE file.
但有時,DLL 文件會附帶一些 LIB 文件,因此:
But sometimes, there're some LIB files coming with the DLL files, so:
- 這些 LIB 文件有什么用?
- 他們如何實現目標?
- 有什么工具可以讓我檢查這些 LIB 文件的內部結構嗎?
查了一下維基百科,我記得這些LIB文件叫做import library.但我想知道它如何與我的主應用程序和動態加載的 DLL 配合使用.
After checking wikipedia, I remember that these LIB files are called import library. But I am wondering how it works with my main application and the DLLs to be dynamically loaded.
正如 RBerteig 所說,在與 DLL 一起生成的 LIB 文件中有一些存根代碼.所以調用順序應該是這樣的:
Just as RBerteig said, there're some stub code in the LIB files born with the DLLs. So the calling sequence should be like this:
我的主應用程序 --> LIB 中的存根 --> 真正的目標 DLL
My main application --> stub in the LIB --> real target DLL
那么這些 LIB 中應該包含哪些信息?我可以想到以下幾點:
So what information should be contained in these LIBs? I could think of the following:
- LIB 文件應包含相應 DLL 的完整路徑;因此 DLL 可以由運行時加載.
- 每個 DLL 導出方法的入口點的相對地址(或文件偏移量?)應該在存根中進行編碼;因此可以進行正確的跳轉/方法調用.
我說得對嗎?還有什么嗎?
Am I right on this? Is there something more?
順便說一句:有什么工具可以檢查導入庫嗎?如果我能看到它,就不會再有疑問了.
推薦答案
鏈接到 DLL 文件可以隱式在compile鏈接時發生,或顯式 在運行時.無論哪種方式,DLL 最終都會加載到進程內存空間中,并且其所有導出的入口點都可供應用程序使用.
Linking to a DLL file can occur implicitly at compile link time, or explicitly at run time. Either way, the DLL ends up loaded into the processes memory space, and all of its exported entry points are available to the application.
如果在運行時顯式使用,您可以使用 LoadLibrary()
和 GetProcAddress()
手動加載 DLL 并獲取指向您需要調用的函數的指針.
If used explicitly at run time, you use LoadLibrary()
and GetProcAddress()
to manually load the DLL and get pointers to the functions you need to call.
如果在程序構建時隱式鏈接,則程序使用的每個 DLL 導出的存根從導入庫鏈接到程序,并且這些存根在進程啟動時加載 EXE 和 DLL 時更新.(是的,我在這里簡化了很多……)
If linked implicitly when the program is built, then stubs for each DLL export used by the program get linked in to the program from an import library, and those stubs get updated as the EXE and the DLL are loaded when the process launches. (Yes, I've simplified more than a little here...)
那些存根需要來自某個地方,在 Microsoft 工具鏈中,它們來自一種特殊形式的 .LIB 文件,稱為導入庫.所需的 .LIB 通常與 DLL 同時構建,并且包含從 DLL 導出的每個函數的存根.
Those stubs need to come from somewhere, and in the Microsoft tool chain they come from a special form of .LIB file called an import library. The required .LIB is usually built at the same time as the DLL, and contains a stub for each function exported from the DLL.
令人困惑的是,同一庫的靜態版本也將作為 .LIB 文件提供.沒有簡單的方法可以區分它們,除了作為 DLL 導入庫的 LIB 通常比匹配的靜態 LIB 小(通常小得多).
Confusingly, a static version of the same library would also be shipped as a .LIB file. There is no trivial way to tell them apart, except that LIBs that are import libraries for DLLs will usually be smaller (often much smaller) than the matching static LIB would be.
如果您使用 GCC 工具鏈,順便說一句,您實際上不需要導入庫來匹配您的 DLL.移植到 Windows 的 Gnu 鏈接器版本可以直接理解 DLL,并且可以即時合成大多數所需的存根.
If you use the GCC toolchain, incidentally, you don't actually need import libraries to match your DLLs. The version of the Gnu linker ported to Windows understands DLLs directly, and can synthesize most any required stubs on the fly.
如果您無法抗拒知道所有具體細節和實際情況,那么 MSDN 總有一些東西可以提供幫助.Matt Pietrek 的文章 深入了解 Win32 可移植可執行文件格式 非常完整地概述了 EXE 文件的格式以及它如何加載和運行.自從它最初出現在 MSDN 雜志 ca 以來,它甚至被更新以涵蓋 .NET 和更多內容.2002.
If you just can't resist knowing where all the nuts and bolts really are and what is really going on, there is always something at MSDN to help. Matt Pietrek's article An In-Depth Look into the Win32 Portable Executable File Format is a very complete overview of the format of the EXE file and how it gets loaded and run. Its even been updated to cover .NET and more since it originally appeared in MSDN Magazine ca. 2002.
此外,了解如何準確了解程序使用了哪些 DLL 也很有幫助.這個工具是 Dependency Walker,又名depends.exe.它的一個版本包含在 Visual Studio 中,但最新版本可從其作者處獲得,網址為 http://www.dependencywalker.com/.它可以識別在鏈接時指定的所有 DLL(早期加載和延遲加載),還可以運行程序并觀察它在運行時加載的任何其他 DLL.
Also, it can be helpful to know how to learn exactly what DLLs are used by a program. The tool for that is Dependency Walker, aka depends.exe. A version of it is included with Visual Studio, but the latest version is available from its author at http://www.dependencywalker.com/. It can identify all of the DLLs that were specified at link time (both early load and delay load) and it can also run the program and watch for any additional DLLs it loads at run time.
為了與 MSDN 保持一致,我已經改寫了一些早期的文本以在重新閱讀時對其進行澄清,并使用藝術術語隱式和顯式鏈接.
I've reworded some of the earlier text to clarify it on re-reading, and to use the terms of art implicit and explicit linking for consistency with MSDN.
因此,我們可以通過三種方式使庫函數可供程序使用.顯而易見的后續問題是:我該如何選擇哪條路?"
So, we have three ways that library functions might be made available to be used by a program. The obvious follow up question is then: "How to I choose which way?"
靜態鏈接是程序本身的大部分鏈接方式.列出所有目標文件,并由鏈接器將它們收集到 EXE 文件中.在此過程中,鏈接器會處理一些瑣碎的工作,例如修復對全局符號的引用,以便您的模塊可以調用彼此的函數.庫也可以靜態鏈接.構成庫的目標文件由庫管理器收集在一個 .LIB 文件中,鏈接器在該文件中搜索包含所需符號的模塊.靜態鏈接的一種效果是,只有程序使用的庫中的那些模塊才鏈接到它;其他模塊被忽略.例如,傳統的 C 數學庫包括許多三角函數.但是如果你鏈接它并使用 cos()
,你最終不會得到 sin()
或 tan()<的代碼副本/code> 除非您還調用了這些函數.對于具有豐富功能集的大型庫,這種選擇性地包含模塊很重要.在許多平臺(例如嵌入式系統)上,與可用于在設備中存儲可執行文件的空間相比,可在庫中使用的代碼的總大小可能很大.如果沒有選擇性的包含,就很難管理為這些平臺構建程序的細節.
Static linking is how the bulk of the program itself is linked. All of your object files are listed, and get collected together in to the EXE file by the linker. Along the way, the linker takes care of minor chores like fixing up references to global symbols so that your modules can call each other's functions. Libraries can also be statically linked. The object files that make up the library are collected together by a librarian in a .LIB file which the linker searches for modules containing symbols that are needed. One effect of static linking is that only those modules from the library that are used by the program are linked to it; other modules are ignored. For instance, the traditional C math library includes many trigonometry functions. But if you link against it and use cos()
, you don't end up with a copy of the code for sin()
or tan()
unless you also called those functions. For large libraries with a rich set of features, this selective inclusion of modules is important. On many platforms such as embedded systems, the total size of code available for use in the library can be large compared to the space available to store an executable in the device. Without selective inclusion, it would be harder to manage the details of building programs for those platforms.
然而,在每個運行的程序中擁有相同庫的副本會給通常運行大量進程的系統帶來負擔.使用正確類型的虛擬內存系統,具有相同內容的內存頁面只需要在系統中存在一次,但可以被多個進程使用.這有利于增加包含代碼的頁面可能與盡可能多的其他正在運行的進程中的某個頁面相同的機會.但是,如果程序靜態鏈接到運行時庫,那么每個程序都有不同的函數組合,每個函數都布置在處理不同位置的內存映射中,并且沒有很多可共享的代碼頁,除非它是一個完全獨立的程序在多個進程中運行.因此,DLL 的想法獲得了另一個主要優勢.
However, having a copy of the same library in every program running creates a burden on a system that normally runs lots of processes. With the right kind of virtual memory system, pages of memory that have identical content need only exist once in the system, but can be used by many processes. This creates a benefit for increasing the chances that the pages containing code are likely to be identical to some page in as many other running processes as possible. But, if programs statically link to the runtime library, then each has a different mix of functions each laid out in that processes memory map at different locations, and there aren't many sharable code pages unless it is a program that all by itself is run in more than process. So the idea of a DLL gained another, major, advantage.
庫的 DLL 包含其所有函數,可供任何客戶端程序使用.如果許多程序加載該 DLL,它們都可以共享其代碼頁.每個人都贏了.(好吧,直到你用新版本更新一個 DLL,但這不是故事的一部分.谷歌 DLL 地獄的故事.)
A DLL for a library contains all of its functions, ready for use by any client program. If many programs load that DLL, they can all share its code pages. Everybody wins. (Well, until you update a DLL with new version, but that isn't part of this story. Google DLL Hell for that side of the tale.)
因此,在規劃新項目時要做出的第一個重大選擇是在動態和靜態鏈接之間進行.使用靜態鏈接,您需要安裝的文件更少,并且您不受第三方更新您使用的 DLL 的影響.但是,您的程序更大,并且它不是 Windows 生態系統的好公民.使用動態鏈接,您需要安裝更多文件,您可能會在第三方更新您使用的 DLL 時遇到問題,但您通常對系統上的其他進程更友好.
So the first big choice to make when planning a new project is between dynamic and static linkage. With static linkage, you have fewer files to install, and you are immune from third parties updating a DLL you use. However, your program is larger, and it isn't quite as good citizen of the Windows ecosystem. With dynamic linkage, you have more files to install, you might have issues with a third party updating a DLL you use, but you are generally being friendlier to other processes on the system.
DLL 的一大優點是無需重新編譯甚至重新鏈接主程序即可加載和使用它.這可以允許第三方庫提供者(例如 Microsoft 和 C 運行時)修復他們庫中的錯誤并分發它.一旦最終用戶安裝了更新的 DLL,他們會立即從使用該 DLL 的所有程序中的錯誤修復中受益.(除非它破壞了某些東西.請參閱 DLL Hell.)
A big advantage of a DLL is that it can be loaded and used without recompiling or even relinking the main program. This can allow a third party library provider (think Microsoft and the C runtime, for example) to fix a bug in their library and distribute it. Once an end user installs the updated DLL, they immediately get the benefit of that bug fix in all programs that use that DLL. (Unless it breaks things. See DLL Hell.)
另一個優勢來自隱式加載和顯式加載的區別.如果您進行顯式加載的額外工作,那么在編寫和發布程序時,該 DLL 甚至可能不存在.例如,這允許可以發現和加載插件的擴展機制.
The other advantage comes from the distinction between implicit and explicit loading. If you go to the extra effort of explicit loading, then the DLL might not even have existed when the program was written and published. This allows for extension mechanisms that can discover and load plugins, for instance.
這篇關于導入庫如何工作?細節?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!