你能帮我理解,为什么从 dll 导入函数和数据时需要 .lib 文件吗?
我听说它包含来自相应 dll 的导出函数和数据元素的列表,但是当我使用 CFF Explorer 探索我的 dll 时,我发现 dll 已经具有导出函数的地址,因此理论上我可以链接我的带有 .dll 的程序,无需任何附加文件。
您能否更详细地解释一下 .lib 文件中存储了哪些数据。
而且,是的,我知道,Visual Studio 强制我们将 .lib 文件添加到附加依赖项部分,但为什么它真的需要它们?
当你的源代码静态地调用导出的 DLL 函数,或者静态地访问导出的 DLL 变量,这些引用将作为指针编译到可执行文件的中间对象文件中,其值在运行时填充。
当链接器组合编译器生成的目标文件以生成最终的可执行文件时,它必须弄清楚所有编译器生成的引用实际引用的内容。如果它无法匹配对可执行文件中某些代码段的给定引用,则需要将其与外部 DLL 匹配。因此它需要知道要查看哪些 DLL,以及这些 DLL 如何导出内容。 DLL 可以按名称或序号导出给定的函数/变量,因此链接器需要一种方法将代码引用所使用的标识符映射到 DLL 中的特定条目。EXPORTS
具体表.dll
文件(特别是在按序数导出内容的情况下)。静态链接.lib
文件为链接器提供该映射信息(即FunctionA
映射到序号123
in DLL XYZ.dll
, FunctionB
映射到名称_FunctionB@4
in DLL ABC.dll
, etc).
然后链接器可以填充IMPORTS
可执行文件的表,其中包含有关适当的信息EXPORTS
所需的条目,然后使代码中的 DLL 引用指向正确的IMPORTS
条目(如果链接器无法解析编译器生成的对可执行文件中的一段代码或对特定 DLL 导出的引用,它将因“无法解析的外部”错误而中止)。
然后,当您的可执行文件在运行时加载时,操作系统加载器会查看IMPORTS
表来知道需要哪些 DLL 导出,因此它可以将适当的 DLL 加载到内存中并更新表中的条目IMPORTS
具有基于每个 DLL 的实际内存地址的表EXPORTS
表(如果引用的 DLL 加载失败,或者引用的导出失败,操作系统加载程序将中止加载可执行文件)。这样,当您的代码调用 DLL 函数或访问 DLL 变量时,这些访问就会到达正确的位置。
如果你的源代码,事情会非常不同动态地通过显式调用访问 DLL 函数/变量GetProcAddress()
在运行时。在这种情况下,静态链接.lib
这些访问不需要文件,因为您自己的代码正在处理将 DLL 加载到内存中并定位它想要使用的导出。
然而,还有第三个选项将上述场景混合在一起:您可以编写代码来访问 DLL 函数/变量静态地但使用你的链接器延迟加载功能(如果有的话)。在这种情况下,你仍然需要静态链接.lib
您访问的每个延迟加载 DLL 的文件,但链接器填充一个单独的DELAYLOAD
可执行文件中的表包含对 DLL 导出的引用,而不是填充IMPORTS
桌子。它将编译器生成的 DLL 引用指向编译器 RTL 中的存根,该存根将用以下地址替换引用GetProcAddress()
当存根在运行时第一次被访问时,从而避免了操作系统加载器在加载时填充引用的需要。即使 DLL 导出在加载时不存在,这也允许您的可执行文件正常运行,并且如果从未使用过 DLL,甚至可能根本不需要加载 DLL(当然,如果您的可执行文件确实尝试访问 DLL 导出)动态地并且无法加载,您的代码可能会崩溃,但这是一个单独的问题)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)