在没有 .lib 文件的程序集中调用 DLL 的导出函数

Posted

技术标签:

【中文标题】在没有 .lib 文件的程序集中调用 DLL 的导出函数【英文标题】:Call exported functions of DLL in assembly without .lib file 【发布时间】:2021-02-15 13:07:20 【问题描述】:

所以我目前正在尝试在我的程序集文件中调用 dll 的导出函数。 DLL 与我的 asm 程序在同一目录中,我没有 .lib 文件。

这是我的代码:

EXTERN __imp__CreateCompressor@12:PROC
EXTERN __imp__Compress@24:PROC
EXTERN __imp__CloseCompressor@4:PROC

.code
START:
            push 2 ;COMPRESS_ALGORITHM_MSZIP
            push 0
            push  OFFSET hCompress
            call    __imp__CreateCompressor@12

            push 0 ;CompressedDataSize
            push DWORD ptr [DataSize] ;CompressedBufferSize
            push eax ;CompressedBuffer
            push DWORD ptr [DataSize]
            push DWORD ptr [pBuf3]
            push DWORD ptr [hCompress]
            call __imp__Compress@24

            push DWORD ptr [hCompress]
            call __imp__CloseCompressor@4
END START

但是我得到了错误:

file.obj : error LNK2001: unresolved external symbol ___imp__CreateCompressor@12
file.obj : error LNK2001: unresolved external symbol ___imp__Compress@24
file.obj : error LNK2001: unresolved external symbol ___imp__CloseCompressor@4
file.exe : fatal error LNK1120: 3 unresolved externals

我是这样组装的: ml file.asm /link /subsystem:console /entry:START

有什么想法吗?

【问题讨论】:

EXTERN __imp__CreateCompressor@12:DWORD 必须是。不是PROC 等等 __imp_ 符号 比你需要添加 Cabinet.lib 用于链接器输入 您必须拥有 .lib 文件才能解决链接器错误。不难获得,它包含在 Windows SDK 中。 【参考方案1】:

您必须使用LoadLibrary()GetProcAddress() 函数来加载库并从您要调用的函数中获取地址。

【讨论】:

可以,但不是必须的。与 Cabinet.lib 更好的链接 @RbMm,OP说他没有lib文件,所以他必须动态加载dll 这个库是 microsoft SDK 的一部分。所以所有需要 - 只需下载它 @RbMm,在这种情况下,这确实是一个解决方案。 :) lib-files 并不是特别神奇,您可以获取函数名称列表并使用 lib 实用程序从中制作 lib-file .. OP 甚至没有需要这样做,因为这个 lib-file 已经存在【参考方案2】:

要启用Load-Time Dynamic Linking,链接器需要一个导入库。

如果没有导入库,您将不得不使用Run-Time Dynamic Linking。

或者,您可以自己生成一个导入库。最简单的方法是编写一个适当的Module-Definition (.Def) File 并让Microsoft Librarian Manager (LIB.exe) 生成一个导入库。

【讨论】:

不认为 .def 在这里就足够了。如果只使用def,我们无法设置多少个参数有作用。所以不可能生成说__imp__Compress@24。但可能将 defc/c++ 结合使用,我们在其中定义了虚拟函数“实现”,例如void __stdcall Compress(int,int,int,int,int,int) - 这已经在 lib 中给出了__imp__Compress@24 @rbm .def 文件足以创建导入库。导入库足以描述在哪里可以找到符号,这就是问题所要求的。 你错了 - 链接器怎么知道,如何只在 x86 中用 def 装饰符号?如果我们声明Compress - lib 中必须有什么符号? _Compress ? _Compress@0 ? _Compress@4 ? _Compress@24 ? _Compress@32 ? @Compress@8 ? @rbm 没有人建议链接器需要猜测。链接器只解析符号。由于 .def 文件包含修饰符号名称,因此在使用从该 .def 文件生成的导入库时无需进行事后猜测。 好的,我们把Compress@24放到def文件中。链接器将_Compress@24__imp__Compress@24 放入库中,但_Compress@24 在生成的PE 中作为导入名称。但我们需要Compress(因为cabinet.dll导出这样的Compress没有装饰)

以上是关于在没有 .lib 文件的程序集中调用 DLL 的导出函数的主要内容,如果未能解决你的问题,请参考以下文章

c语言怎么调用dll文件

Android studio - 从 dll 文件或 lib 文件调用函数

LIB文件和DLL文件的作用

如何在使用反射加载的程序集中使用 Castle.Windsor

Qt Creator开发Android程序 如何调用C语言的dll

静态库 动态库 调用