使用 __declspec(dllimport) 导入函数调用

来源:互联网 发布:软件规模大小 编辑:程序博客网 时间:2024/06/05 10:23

下列代码示例显示如何使用 _declspec(dllimport) 将函数调用从 DLL 导入到应用程序中。假设 func1 是驻留在某个 DLL 中的函数,而此 DLL 与包含 main 函数的 .EXE 文件是分开的。

不使用 __declspec(dllimport),给出此代码:

int main(void) 
{        func1();}

编译器生成类似下面的代码:

call func1

链接器将调用翻译成下面的内容:

call 0x4000000         ; The address of 'func1'.

如果 func1 存在于另一个 DLL 中,链接器将无法直接解析此代码,因为它无法得知 func1 的地址。在 16 位环境中,链接器将此代码地址添加到 .EXE 中的某个列表,而加载程序在运行时会用正确的地址修补该列表。在 32 位环境中,链接器生成一个地址为它所知的 thunk。该 thunk 看起来像下面这样:

0x40000000:    jmp DWORD PTR __imp_func1

其中,imp_func1func1 的槽在 .EXE 文件的导入地址表中的地址。这样,链接器就知道了所有的地址。加载程序只需在加载时更新 .EXE 文件的导入地址表,一切就会正常运行。

因此,使用 __declspec(dllimport) 更好,因为链接器不生成不必要的 thunk。thunk 使代码变大(在 RISC 系统上代码它可能是若干指令),并且会降低缓存性能。如果通知编译器函数在 DLL 中,编译器会为您生成间接调用。

因此,现在此代码:

__declspec(dllimport) void func1(void);int main(void) {        func1();}

生成此指令:

call DWORD PTR __imp_func1

没有 thunk 和 jmp 指令,所以代码更小且更快。

另一方面,对于 DLL 内部的函数调用,您希望不必使用间接调用。您已经知道函数的地址。间接调用前需要时间和空间来加载和存储函数的地址,因此直接调用总是更快更小。当从 DLL 本身外部调用 DLL 时,您仅希望使用 __declspec(dllimport)。生成 DLL 时不要在此 DLL 的内部函数上使用 __declspec(dllimport)

原创粉丝点击