从.dll导入函数时,为什么需要.lib文件?

时间:2019-05-10 22:58:13

标签: c++ visual-studio dll lib

您能帮我理解为什么从dll导入函数和数据时为什么需要.lib文件吗?

我听说,它包含来自相应dll的导出函数和数据元素的列表,但是当我使用CFF Explorer探索我的dll时,我发现dll已经具有导出函数的地址,因此从理论上讲我可以链接我的.dll的程序,没有任何其他文件。

您能否详细解释一下.lib文件中存储的数据类型?
而且,是的,我知道,Visual Studio迫使我们将.lib文件添加到其他依赖项部分,但是为什么它真的需要它们?

2 个答案:

答案 0 :(得分:5)

当源代码静态调用导出的DLL函数,或者静态访问导出的DLL变量时,这些引用将作为指针编译到可执行文件的中间目标文件中,其值将得到在运行时填充。

当链接器将编译器生成的目标文件组合成最终可执行文件时,它必须弄清楚所有编译器生成的引用实际上是指什么。如果它不能匹配给定引用对可执行文件中某些代码的引用,则需要将其与外部DLL匹配。因此,它需要知道什至要查看哪些DLL,以及这些DLL如何导出内容。 DLL可以按名称或按序号导出给定的函数/变量,因此链接器需要一种方法,将代码引用所使用的标识符映射到特定EXPORTS文件的.dll表中的特定条目(尤其是按常规方式导出商品时)。静态链接.lib文件为链接器提供了该映射信息(即FunctionA映射到DLL 123中的序数XYZ.dllFunctionB映射到名称{{1 }},例如DLL _FunctionB@4等。

然后,链接器可以使用有关所需的ABC.dll条目的信息填充可执行文件的IMPORTS表,然后使代码中的DLL引用指向正确的EXPORTS条目(如果链接器无法将编译器生成的引用解析为可执行文件中的一段代码或特定的DLL导出,则会因“无法解析的外部”错误而中止。)

然后,在运行时加载可执行文件时,OS Loader会查看IMPORTS表以了解需要哪些DLL导出,因此可以将适当的DLL加载到内存中并更新其中的条目。 IMPORTS表,其实际内存地址基于每个DLL的IMPORTS表(如果引用的DLL无法加载,或者找不到引用的导出,则OS Loader将中止加载可执行文件) 。这样,当您的代码调用DLL函数或访问DLL变量时,这些访问将转到正确的位置。

如果源代码通过运行时通过显式调用EXPORTS来动态地访问DLL函数/变量,则情况将大为不同。在那种情况下,这些访问不需要静态链接GetProcAddress()文件,因为您自己的代码正在处理将DLL加载到内存中并找到要使用的导出文件。

但是,有第三个选项将上述情况融合在一起:您可以编写代码以静态方式访问DLL函数/变量,但可以使用链接器的延迟加载功能(如果有)。在这种情况下,对于访问的每个延迟加载的DLL,您仍然需要静态链接.lib文件,但是链接程序会在可执行文件中使用对DLL导出的引用填充单独的.lib表,而不是填充DELAYLOAD表。它将编译器生成的DLL引用指向您的编译器RTL中的存根,当在运行时首次访问存根时,它将用IMPORTS中的地址替换该引用,从而避免了对这些存根的引用。由OS Loader在加载时填充。即使加载时不存在DLL导出,这也可使您的可执行文件正常运行,并且即使从未使用过DLL也可能根本不需要加载DLL(当然,如果您的可执行文件确实尝试访问DLL导出)动态并且无法加载,您的代码可能会崩溃,但这是一个单独的问题。

答案 1 :(得分:1)

  

我听说它包含来自相应dll的导出函数和数据元素的列表,但是当我使用CFF Explorer探索我的dll时,我发现该dll已经具有导出函数的地址,因此从理论上讲可以将我的程序与.dll链接,而无需任何其他文件。

作为一个为什么不能总是正常工作的简单示例,请考虑一个可执行文件,该可执行文件访问两个DLL,一个用于Winsock筛选器,另一个用于分配器。并说在这台特定的机器上,Winsock筛选器DLL恰好也实现了具有相同API的分配器,而分配器DLL恰好也实现了具有相同API的Winsock筛选器。编译器如何知道从哪个DLL访问哪个API函数?库文件包含用于访问DLL的意图,即您要访问的API和函数。

重要的是,没有诸如“相应的DLL”之类的东西。在不同的系统上可能会有不同的DLL文件。链接器需要知道的是它应该可以依赖的DLL外观,而不是您可能碰巧在某些特定系统上使用的DLL。

例如,假设DLL文件包含一个分配器。您可能会有一个DLL文件用于调试器分配器,一个DLL文件具有针对特定CPU版本的优化,而另一个文件分配给使用新的实验算法的分配器。链接器需要知道的是所有这些DLL文件都实现的API,而不是任何一个文件中的特定实现。

您可以produce a LIB file from a DLL file,但是您可能最终会构建一个在使用其他版本的DLL文件时无法运行的可执行文件。您将不得不假设该特定的DLL恰好要做的就是与实现相同API的所有其他DLL恰好一样。