导入库如何工作以及为什么 MinGW 不需要它们?

How do import libraries work and why doesn't MinGW need them?

我查看了这个页面:An In-Depth Look into the Win32 Portable Executable File Format

说明链接器需要导入库,因为编译器无法区分正常函数调用和API-函数调用。但他们还说 __declspec(dllimport) 将函数调用指定为 API-Call 因此链接器链接到 __imp_[function-姓名]但是 使用这个关键字,编译器应该知道这是对 API-Function 的调用。

为什么链接器还需要导入库?编译器可以通过在函数名称前添加 __imp_ 来将此符号标记为已导入,并可以调用函数指针(这是一个尚未解析的符号)并且链接器可以替换此符号(因为它看到这是一个 API call) 与 IAT 条目的地址。

以及为什么 MinGW-linker 可以直接使用 "MinGW-DLLs" 而 Visual-Studio 链接器需要导入库?

当我阅读 post 时,还提出了一些其他问题。在完成与最终可执行文件的链接之前,"dlltool (or linker)"(创建导入库的那个)如何知道 IAT 条目的位置?我认为 IAT 条目将在链接时与最终可执行文件一起构建。 post 表示,每个 API-Call 在 IAT 表中都有一个固定位置,不管将链接多少个 DLL。我无法想象那是如何实现的。

如 MinGW 清楚地演示的那样,可以 link 在没有导入库的情况下生成 DLL。因此,问题是为什么 MSVC 决定省略此功能。

原因主要是历史原因。

然后在 1983 年,当 Windows 出现并且设计 DLL 时,有许多来自不同供应商的工具链(编译器,linker)。要求供应商为少数 OS linking "DLLs" 提供支持显然不是一种选择。

因此他们决定编写一个工具来生成一个库,每个人和他们的狗都可以 link 对抗,即使 link 人完全不了解 DLL。

此外,导入库提供了一些在 3 年前非常重要但现在几乎已过时的功能。首先是按序号导入符号的能力——即 DLL 可以选择不提供任何名称,只提供地址列表;序号是此列表中的索引。当 RAM 数量受到严重限制时才有意义。

其次是对不同名称修改方案的支持。即使在 C 中也有一个名称修改方案,例如 FooBar 可能变成 _FooBar@4 (这取决于平台和调用约定)。对于 DLL 在每个支持的平台上导出 "FooBar" 以保持一致性是非常有意义的(并且它使 GetProcAddress() 用户的生活更轻松)。导入库实现了_FooBar@4到FooBar的映射。

这是基于 Raimond Chen 的博客 (1, 2),他从一开始就参与 Windows 开发。