我正在寻找有关 dlltool 的 --add-indirect 选项的更多信息。你什么时候使用这个选项?它有什么作用?
来自 binutils 的有关此选项的帮助信息:
-a
--add-indirect
指定当
dlltool
创建导出文件时,它应该添加一个允许在不使用导入库的情况下引用导出函数的部分。不管这意味着什么!
首先,让我们明确什么是导出文件。创建 DLL 需要导出文件。该文件与构成 DLL 主体(即函数、类等)的目标文件(由编译器生成)链接,并处理 DLL 与外部世界之间的接口。这是一个二进制文件,可以通过在创建或读取文件时提供-e
选项来创建它。dlltool
*.def
您必须了解的下一个术语是import library。一些消费者应用程序使用 DLL 的方法之一是将此应用程序与 DLL 链接起来,以便消费者可以使用从 DLL 导出的所有功能。这种到 DLL 的链接通常是通过链接到一个导入库来完成的,该库本质上是一个辅助静态库,其中包含一个导入地址表(IAT),它允许消费者引用所有 DLL 导出的功能。例如,每个引用的 DLL 函数在 IAT 中都包含自己的条目。在运行时,IAT 会填充适当的地址,这些地址直接指向单独加载的 DLL 中的相应函数。
现在让我们手动创建一个 DLLdlltool
并gcc
让您感受发生了什么:
gcc -c library.c
产生library.o
,
dlltool -e exports.o -l library.dll.a library.o
生成导出文件exports.o
和导入库library.dll.a
(.dll.a
是 GCC 生成的导入库的常规后缀,强调导入库实际上是静态的.a
,但针对 DLL 的.dll
),
gcc library.o exports.o -o library.dll
产生library.dll
,
gcc consumer.o library.dll.a -o consumer
consumer.exe
生成与 .链接的可执行文件library.dll
。
注意:以上是创建 DLL 的手动过程,不鼓励在生产中这样做,因为 GCC 将所有这些逻辑包装在一个优化的调用中:
gcc -shared -o library.dll library.o -Wl,--out-implib,library.dll.a
回到正轨,现在我们知道了基本的术语和目的,我们可以很容易地解释 help about 中写的内容--add-indirect
:
指定当
dlltool
创建导出文件时,它应该添加一个允许在不使用导入库的情况下引用导出函数的部分。不管这意味着什么!
让我们将其应用于前面的示例。在这种情况下,exports.o
将已经包含 IAT,因此结果library.dll
也将包含该信息,因此我们不需要导入库library.dll.a
,因为现在我们可以直接链接到library.dll
自身:
gcc consumer.o library.dll -o consumer
它是否有用是一个非常主观的问题。我想从我们(程序员/用户)的角度来看,它几乎没有用,因为dlltool
无论如何都不应该明确地(即通过直接调用)来完成 DLL 的创建和链接,而应该通过 GCC 前端来完成(如前所述以上)。从构建诸如工具链(如 GCC 本身)之类的开发工具的角度来看,这可能很有用,因为与上述示例类似的东西实际上可能由 GCC 本身在幕后使用来执行gcc -shared -o library.dll ...
等。
最后,通常不鼓励直接链接 DLL。虽然它在最新版本的 MinGW/MinGW-w64 上运行良好,但过去已知它存在错误。此外,如果禁用伪重定位,则与 DLL 的直接链接可能会导致某些运行时问题。此外,这是 MSVC 将消费者与 DLL 链接起来的官方方式,即没有导入库,MSVC 根本无法进行链接,这也可能是您应该始终使用导入库的原因。请记住,DLL 与 Linux 上的共享对象 (SO) 不同:它们的用例相同,但它们的实现基于不同的技术。