透过汇编另眼看世界之DLL导出函数调用

前言:我一直对DLL技术充满好奇,一方面是因为我对DLL的导入/导出机制还不是特别的了解,另一面是因为我发现:DLL技术在Windows平台下占有重要的地位,几乎所有的Win32 API都是以导出函数的形式存放于不同的DLL文件中,在DLL方面的学习是任何一个想深入研究Windows内部机制的Windows程序员都不可能回避的事实。我在查阅了大量的文章后,对DLL技术有了一定的了解,所以我写了这篇文章来总结和整理我的思路,也为以后深入的学习提供宝贵的资料。

对于如何制作DLL,网上有很多资料,我这里就不多罗嗦了。现在假设我们已经成功生成了一个Win32 DLL,这个DLL的名字是DllInDepth.dll,它只导出了一个简单的C++函数:
__declspec(dllexport) void foobar(int iValue) {
    printf(
"The value is %d.",iValue);
}

接下来我建立了一个Win32 Console Application。我想把这个应用程序(TestApp)作为客户程序,使用DLL导出的函数。首先我尝试在代码中直接使用这个函数:
int _tmain(int argc, _TCHAR* argv[]) {
    foobar(
5);
    
return 0;
}

编译器不高兴了,给出了这样的错误提示:
error C2065: “foobar” : 未声明的标识符

哦,编译器不知道符号"foobar"是什么东东,当然会报错了。这个好办,我就在TestApp程序中引用声明了foobar函数的头文件:
#include  " DllInDepth.h "
int  _tmain( int  argc, _TCHAR *  argv[]) {
    foobar(
5 );
    
return   0 ;
}

这下编译器是满意了,但是连接器又不高兴了,连接器报错:
error LNK2019: 无法解析的外部符号  " __declspec(dllimport) void __cdecl foobar(int) "  (__imp_ ? foobar@@YAXH@Z)

仔细想想,连接器不高兴是有道理的。连接器的主要任务就是将处于不同编译单元(Compilation Unit)的汇编代码"组合/加工"成一个可执行文件,找不到目标文件,连接器拿什么来"加工"呀。这个也好办,在编译DLL的时候,不是生成了一个导出库么?就让连接器连接这个库就可以了。这下问题都解决了,TestApp也成功生成了,怀着激动的心情迫不及待的运行TestApp,一个对话框和"嘣"的一声给了我当头一棒:无法找到需要的DLL

哦,应用程序在装载所需要的DLL时,会按照一定的顺序搜寻指定的目录来寻找需要的DLL。如果搜寻过程结束了也没有找到需要的DLL,应用程序就会停止运行。这个也好办,将DLLDllInDepth.dll复制到TestApp所在的目录不就可以了。

到了现在,TestApp总算能够正确的运行起来了。从以上的"挫折"可以看出,一个DLL的正确运行,需要三个"职能部门"的通力合作:
1.编译器。只有正确引用了相应的头文件,编译器才能正确编译。
2.连接器。只有正确连接了相应的导出库,连接器才能正确连接。
3.装载器。只有正确设置了DLL的路径,当需要它的时候它才能正确被装载到内存中。

接下来我们将深入DLL的编译和连接,了解更多实隐藏在编译器和连接器背后的东西。这次我们使用的"利器"仍然是汇编代码,希望能从汇编代码中找到一些"蛛丝马迹"。下面是TestApp中关键的代码和相应的汇编代码:
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值