我看了这个页面: 深入了解Win32可移植可执行文件格式
它解释了链接器需要一个导入库,因为编译器无法区分正常的函数调用和API函数调用。 但他们也说, __imp_[ function-name ]
(dllimport)指定一个函数调用是一个API调用,所以链接器链接到__imp_[ function-name ]
。 但是使用这个关键字,编译器应该知道这是对API函数的调用。
为什么链接器仍然需要导入库? 编译器可以通过将__imp_
添加到函数名称来标记这个符号,并且可以调用函数指针(这是一个尚未parsing的符号),链接器可以用这个符号replace这个符号(因为它看到了这个API调用) IAT条目的地址。
为什么MinGW-linker直接使用“MinGW-DLLs”,而Visual-Studio链接器需要一个导入库?
当我阅读这篇文章时,还提出了其他一些问题。 在与最终可执行文件进行连接之前,“dlltool(或连接器)”(哪一个创build导入库)如何知道IAT条目的位置? 我认为IAT条目将在链接时与最终的可执行文件构build。 这篇文章说,每个API调用在IAT表中都有一个固定的位置,而不用介意有多less个DLL会被链接。 我无法想象如何实现。
MinGW清楚地表明,可以链接到没有导入库的DLL。 所以问题是为什么MSVC决定省略这个功能。
原因主要是历史性的。
当时在1983年,当Windows出现并设计了DLL时,来自不同厂商的工具链(编译器,链接器)很多。 要求供应商实现对少数操作系统链接“DLL”的支持显然不是一种选择。
所以他们决定编写一个工具来生成一个每个人和他们的狗都可以链接的库,即使链接器完全不知道DLL。
除了进口图书馆提供了一些在30年前至关重要的功能,但现在已经过时了。 首先是按顺序导入一个符号的能力 – 也就是DLL有一个选项,根本不提供任何名称,只有一个地址列表; 序号是这个列表中的一个索引。 当RAM的数量受到严重限制时,就变得非常灵敏了。
其次是支持不同的名称修改方案。 即使在C中,也有一个名称改变方案,例如FooBar可能会变成_FooBar @ 4(这取决于平台和调用约定)。 对于一个DLL在每个支持的平台上导出“FooBar”以保持一致性(使得GetProcAddress()用户的生活更简单),这是非常合理的。 导入库实现从_FooBar @ 4到FooBar的映射。
这是基于从一开始就参与Windows开发的Raimond Chen的博客( 1,2 )。