Chinaunix首页 | 论坛 | 博客
  • 博客访问: 166472
  • 博文数量: 33
  • 博客积分: 2143
  • 博客等级: 大尉
  • 技术积分: 807
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 10:24
个人简介

Show me the money

文章分类

全部博文(33)

文章存档

2015年(1)

2013年(1)

2011年(12)

2010年(14)

2009年(2)

2008年(2)

2005年(1)

我的朋友

分类: C/C++

2013-07-29 17:02:37

众所周知,dll有两种使用方式:
1. implicit loading:链接时需要指定dll。应用程序启动时由os自动加载所需要的DLL
2. explicit loading:链接时无需指定dll。应用程序启动后自行加载所需的DLL,然后
  2.1.  定义一个与函数原型匹配的函数指针,
  2.2.  通过GetProcAddess获取dll函数的地址
  2.3.  通过函数指针进行函数调用
  这样做也有一些缺点:
    A. 函数指针不能一般不能与dll中的导出函数同名;因为编译的时候一般都会包含导出函数声明的头文件,如果重名就会报redefinition错误。函数指针与导出函数不同名会使得代码没有兼容性(万一以后要把程序改成implicit loading的方式,又需要对把所有的函数指针改回成导出函数)。
    B. 对于每一个函数调用,都需要重复以上3个步骤。如果需要调用的函数很多,手工码代码的效率很低,机械劳动也很无趣。

在此,笔者找到一种方法,在explicit loading中,可以使函数指针与dll中的exported函数同名,并且将获取函数地址的细节隐藏起来,使之对用户完全透明。这既提高了编码效率,又保证了代码的兼容性。具体步骤如下:

1. 通过Visual Studio的dumpbin工具,获取dll中所有的export函数列表
2. 通过脚本自动生成helper代码
2.1  对于每一个export函数,生成以下汇编代码(MASM格式)

__imp_foo        dd  _foo_init

...

_foo_init:
  call _preload_foo_dll_functions
_foo PROC
  jmp dword ptr [__imp_foo]
_foo ENDP

2.2  对于每一个export函数,生成以下C代码

struct {
  const char *name;
  unsigned long *imp_entry;
} dll_function_entries[] = {
  { "foo", &__imp_foo }
  ...
};
并且自动生成preload_dll_functions函数
void preload_dll_functions(void *hmod)
{
    unsigned int i;
    for(i = 0; i < sizeof(dll_function_entries)/sizeof(dll_function_entries[0]); i++) {
        * dll_function_entries[i].imp_entry = GetProcAddress(hmod, dll_function_entries[i].name);
    }
}
将生成的.c和.S文件加入工程进行编译。

附件中的demo代码依赖于以下工具:
1.  Visual Studio 2010
2.  python3


explicit_call_dll.7z

阅读(2840) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~