找不到用asm编写的dll函数

时间:2014-10-22 17:27:20

标签: c++ visual-studio assembly dll

我的代码是:

HINSTANCE hDll;
hDll = LoadLibrary("FibAsmLib");
myCppProc = GetProcAddress(hDll, "GetFive");

库是corectly加载的,但GetProcAddress返回NULL值。

这就是我的看法:

fibAsm.asm

.486
.model flat, stdcall
.code

GetFive proc
ret 5
GetFive endp
end

asmLib.h

#ifdef FIBASMLIB_EXPORTS
#define FIBASMLIB_API __declspec(dllexport)
#else
#define FIBASMLIB_API __declspec(dllimport)
#endif

FIBASMLIB_API int GetFive();

和asmLib.def

LIBRARY "FibAsmLib"
EXPORTS
GetFive

我找不到问题出在哪里,你有什么线索吗?

//修改

当我在DependencyWalker中运行dll时出现错误:

Error: At least one module has an unresolved import due to a missing export function in an implicitly dependent module.
Error: Modules with different CPU types were found.

现在我确定它的dll错误,但我仍然无法找出问题所在

// EDIT2 我有切入点:

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

// edit3 啊,我没有将.def文件设置为模块定义文件,但现在我无法编译库cus

error LNK2001: unresolved external symbol GetFive   ...FibAsmLib.def

2 个答案:

答案 0 :(得分:2)

您的代码有几个问题。首先,DLL需要一个带有12个字节参数的入口点(传统上称为DllMain),因此您需要为此添加至少一个函数。

其次,至少就我能够找到/得到的东西而言,要导出未破坏的名称,你需要在{{1}中使用external=internal语法}语句,所以你的.def文件应该是这样的:

exports

如果不这样,带有LIBRARY "FibAsmLib" EXPORTS GetFive = _GetFive@0 DllMain = _DllMain@12 的.def文件会找到您编写的GetFive函数,但会导出它的错位名称(exports GetFive)。这很好,但是如果你这样做,你需要在调用_GetFive@0时指定受损的名称:

GetProcAddress

无论如何,当您进行链接时,您还需要指定入口点,例如:

myCppProc = GetProcAddress(hDll, "_GetFive@0");

顺便说一句,当/如果你想看到从DLL导出的名称时,最简单的方法通常是使用link fibAsm.obj /def:asmLib.def /entry:DllMain (显然用实际DLL文件的名称替换dumpbin /exports YouDll.dll想看看)。警告:对于大型DLL,输出可能非常庞大,因此您经常需要将输出管道输出到YourDll.dll之类的内容。

您实际上并不需要导出入口点(事实上,我认为至少某些版本的链接器会发出警告),因此整体文件可能如下所示:

fibasm.asm

less

asmlib.def:

.486
.model flat, stdcall

.code

Entry PROC Inst : DWORD, reason : DWORD, reserved : DWORD
ret 12
Entry ENDP

GetFive PROC
ret 5
GetFive ENDP

end

生成文件:

LIBRARY "FibAsmLib"
EXPORTS
    GetFive = _GetFive@0

至少对我来说,有了这三个,fibasmlib.dll: fibasm.obj asmlib.def link fibAsm.obj /def:asmLib.def /entry:Entry .asm.obj: ml /c $< 成功构建了DLL。

答案 1 :(得分:0)

“LoadLibrary”似乎不会返回NULL - 如果我理解正确的话。

这意味着“DllMain”不是问题;否则LoadLibrary将返回NULL。

许多连接器需要函数名称中的下划线;如果在.DEF文件中命名函数“GetFive”,那么链接器将期望一个实际命名为“_GetFive”的函数,因为所有C编译器都会在每个函数中添加该下划线。

汇编程序代码中的“stdcall”可能就是问题所在。这可能会告诉汇编程序自动生成符号名称。这意味着:汇编程序将“GetFive”重命名为“_GetFive @ 0”(在这种情况下,函数可能必须命名为“GetFive @ 0”而不包含.DEF文件中的下划线)。

为了避免这种情况,我会在汇编程序中使用“cdecl”而不是“stdcall”,尽管函数实际上是一个stdcall函数!这样做将无法从DLL中的汇编程序调用C代码,反之亦然。 (EXE文件中的C代码可以调用DLL中的汇编代码。)

GNU C编译器附带的“objdump”工具可用于检查对象和DLL文件中函数的名称:

此命令将列出目标文件中的所有符号名称(函数和变量):

objdump -t FibAsmLib.obj

您可以看到您的函数是否命名为“GetFive”,“_ GetFive”或“_GetFive @ 0”。

此命令将列出DLL文件中的所有Windows特定信息:

objdump -p FibAsmLib.dll

这个工具输出很长。在输出中间的某个位置,您将找到所有导出的列表(可以使用“GetProcAddress”访问的所有函数)。此列表如下所示:

[Ordinal/Name Pointer] Table
        [   0] GetFive

顺便说一下:“ret 5”没有任何意义!我认为指令应该是“退20”。但是这会导致保护错误,而不是“GetProcAddress”的问题。