如果你正常编写一个静态库,则可能有这样一个需求:需要访问主链接模块的HINSTANCE。我们可以要求主链接模块传递它的实例句柄到一个特殊的初始化函数中,这确实可行,但是人们经常忘记这样做,从而导致奇怪的事情发生。
如果你使用微软的链接器来链接代码,你可以使用一个链接器提供的一个虚拟变量来实现这个需求,如下图所示:
在上面的代码中,我们使用了__Imagebase这个虚拟变量来代表一个模块的DOS头部,它恰好是一个Win32模块开始的地方。换句话说,它实际上是一个模块的基地址。而一个模块的基地址就是一个模块的实例句柄。
那么,这个虚拟变量就是你想要的实例句柄啦。
总结
注意,这里的Imagebase是虚拟地址空间的地址,而不是物理内存。两个不同进程启动之后,它们将会拥有不同的地址空间,从技术上来说,可执行文件可以在整块虚拟地址空间的任意位置被操作系统加载,但操作系统默认将进程加载到0x00400000的位置。
如果有这样一种情况,一个可执行程序,它加载了一些DLL模块,如果这些DLL模块拥有相同的Imagebase,会出现什么问题吗?操作系统会这样进行处理,第一个DLL在指定的Imagebase上加载正常,而第二个会发生地址重载。每个DLL模块的PE结构中都会有一个.reloc节,它会包含和代码更新有关的引用数据。