Win动态连接库基址重置技术

上传人:hs****ma 文档编号:499081306 上传时间:2022-08-29 格式:DOC 页数:15 大小:36KB
返回 下载 相关 举报
Win动态连接库基址重置技术_第1页
第1页 / 共15页
Win动态连接库基址重置技术_第2页
第2页 / 共15页
Win动态连接库基址重置技术_第3页
第3页 / 共15页
Win动态连接库基址重置技术_第4页
第4页 / 共15页
Win动态连接库基址重置技术_第5页
第5页 / 共15页
点击查看更多>>
资源描述

《Win动态连接库基址重置技术》由会员分享,可在线阅读,更多相关《Win动态连接库基址重置技术(15页珍藏版)》请在金锄头文库上搜索。

1、Win32动态连接库基址重置技术摘要本文讨论了Microsoft Windows NT和Microsoft Windows 95动态链接库(dynamic-link library,DLL)基址重置(rebasing)的若干问题(在本文中,Rebasing,基址重置一词指的是在内存空间中改变动态链接库基地址的过程)。随本文章提供了一个应用程序实例和一个动态链接库套件,读者可以从中进行一些比较。引言开发人员常问到的一个问题是,当操作系统对动态链接库(DLL)进行基址重置时,会出现什么效果?基址重置会带来什么损失?有什么办法可以避免这些损失?是否有办法修改代码以减少基址重置所带来的修补(fixup

2、)工作?由于这些问题很有代表性,所以本文将集中讨论一下加载动态链接库(DLL)的有关问题,希望为使用动态链接库(DLL)的读者提供一定的参考。事实上,本文给出的结果也许并不太新奇,也不太具有革命性,比方说:最好选择较大的动态链接库(DLL),而不宜选择一大堆小的动态链接库;确定系统不需要花费很长时间搜索动态链接库;如果操作系统有可能对动态链接库进行基址重置,应尽量避免由此而带来的修补工作(或者也可以使用另一种办法,尽量选定用户基地址,防止基址重置现象的发生)。然而,正如一句古老言语所说的那样,过程即目标(The journey is the goal.)。换句话说,作者在写作本文时,发现了大量

3、的有关动态链接库和内存管理的小问题、小技巧,作者认为,这些问题和技巧是值得与大家分享的。也许,这篇文章更合适的名字应该是动态链接库点滴。在本文中,将给出一个作者自己写的样本测试应用程序,此程序用于测试动态链接库的加载时间。本文还将提供一些测试用的动态链接库。应用程序用于测试动态链接库(DLL)加载时间的测试集结构非常简单,主要包括:使用Microsoft基础类库(Foundation Class libraries,MFC)编写的PAGETEST应用程序,此程序包含两个线程。第一个线程(主应用程序)建立并拥有默件(mutex)对象。此线程对当前时间进行采样,然后调用LoadLibrary函数,

4、以显式方式加载作者提供的库(本文下一节将讨论这些库)。与此同时,第二个线程等待默件(mutex)对象发送信号。所有的库都由动态链接库的入口程序组成。在动态链接库(DLL)入口程序的PROCESS_ATTACH发送点,默件(mutex)对象发送信号。此时,辅助的应用程序线程被唤醒,在调用LoadLibrary函数之前,计算采样时间和当前时间之间的差值。这个时间差值大致上就是DLL装入内存所需的时间。MFC应用程序有一个反复加载和卸载DLL的选项(50次),通过反复加载,可以计算出有意义的平均加载时间。文章不需要讨论应用程序的特性,因为本文中使用的程序都是简单的MFC应用程序,所有的相关代码都存在

5、于显示类中。显示类由CEasyOutputView函数引出,用于提供简单的显示结果。(欲知进一步的细节,请参阅Windows NT Security in Theory and Practice,Windows NT安全性理论与实践)读者应该注意,这种经验式的测试方法有很多缺陷,因此测试结果有可能与实际结果相背离,这主要因为:作者假设时间抽样机制是有效而可靠的,抽样力度足够细。(作者使用了系统性能计数器)作者假设线程切换机制是连续有效的,对唤醒辅助线程所需时间没有非常不良的影响。测试结果在很大程度上,依赖于底层硬件(也就是说,下列一些因素也会对测试结果产生影响,如运行测试程序的计算机速度、所使

6、用的处理器数目、硬盘控制器的速度、等等)。测试结果使用特定版本的软件进行抽样。(操作系统版本、C运行时间库版本、等等。)通常情况下,大多数动态链接库都是隐式加载的,而不是显示加载的。这就要求作出如下假设:隐式加载DLL与显示加载DLL所用的时间一样长,相应的其他参数也相同。更糟糕的是,作者所得到的数据有时相差很大。因此,读者应该有保留地接受这些结果。在测试结果中,更有参考价值的不是加载所需的绝对时间,而是相对时间。换句话说,重要的是调整某一参数对加载行为的影响,以及不同策略之间的加载结果比较。如果读者希望在自己的计算机上重建测试结果,可以按照下一节将讨论的动态链接库定位指令,运行PTAPP.E

7、XE,并在Multiple Test菜单中,选择Run All Tests选项。动态链接库下面是动态链接库与加载时间有关的一些性质:动态链接库的大小。需要重定位的条目数量。动态链接库是否初始化C启动代码。动态链接库是否输出符号。动态链接库是否与其他库隐式链接。操作系统需要多长时间,才能重定位可执行的动态链接库。除了上述因素以外,还有一些独立于动态链接库的因素,也决定着动态链接库加载速度的快慢。例如,底层操作系统、当前计算机上总的工作负荷、应用程序的工作集、动态链接库是否需要基址重置、等等。为简单起见,作者给出18个小的动态链接库(其中有些并不太小),这些DLL几乎代表了以下特性的全部组合:动态

8、链接库大小(可以大也可以小)如果是大的动态链接库,是否需要修正加载时间C运行时间支持(没有支持、隐式链接的、显示链接的)动态链接库输出的符号(yes或no)作者在同一台机器上,在Windows NT版本3.51和Windows 95环境下,将全部18个动态链接库通过各自首选的虚拟地址区,加载到各自首选的基地址中。每个测试程序也首先将动态链接库定位到当前目录中,然后,沿着路径下行搜索,测试将动态链接库定位到当前搜索到的目录中,操作系统所需花费的时间。如前所述,每次测试运行50此,得到统计平均值。作者的第一个发现是,在Windows NT环境下,任何给定的动态链接库的初始加载时间,平均是在以后加载

9、同一个动态链接库所需时间的三倍。这种现象是由Windows NT内存管理设计的副作用造成的:一旦初始加载了某一动态链接库,卸载后,属于此动态链接库映象的页仍然存在内存中;这些页被放在等待列表中(等待列表是系统为丢弃的页维护的一个列表,如果原来的应用程序又需要此列表中的页,或新的应用程序需要访问列表中的页,这些页可以被重新起用。)读者如果想了解有关等待列表的进一步信息,请参阅Helen Custer的Inside Windows NT(Windows NT内幕)一书的194页到196页。从等待列表页中重载动态链接库的页,比从磁盘上重载有关页效率高的多。随着时间的推移,有关的页会从等待列表中移到自

10、由列表中。如果在加载初始动态链接库和加载后续动态链接库之间,有很多内存分配和内存访问操作,两种情况下加载动态链接库所花的时间将不会有太大差别。为模拟上述行为(一定通过多次测试,取得加载动态链接库时间的统计平均值),作者加入了一个选项,此选项允许应用程序尽可能多地占用内存,使等待列表尽快用完。伴随着Windows NT Resource Kit,微软将提供一个小小的实用程序,此程序可以强制将一页从等待列表中取出,此程序是CLEARMEM.EXE。实用上述方法确实十分有效,但遗憾的是,作者释放了所占用的内存之后,加载时间一下变成平均时间的20倍-初始加载时间的7倍。这种现象使作者陷入了一个两难境地

11、:一方面,作者希望得到在正常工作条件下,加载动态链接库的可靠的统计平均时间;另一方面,作者所能得到的唯一的可靠的、一致的时间不是在正常工作条件下得到的。于是,作者使用了如下的冒险策略(但却是合理的方法),解决了这一两难问题:假设初始加载时间和随后的平均加载时间之间的关系是固定的,将测试结果建立在比较加载动态链接库的平均时间的基础上。使用这种办法,在正常工作情况下,所得的比较结果仍然是有意义的。读者如果希望重建动态链接库、加入自己的动态链接库变量、或者只是想了解一下作者如何建立了18个动态链接库,可以继续阅读(或浏览一下)下一小节。否则,可以跳过这小节,直接阅读理论一节。建立动态链接库使用Vis

12、ual C+版本2.2产生makefile,可以建立动态链接库。读者可以在PAGETEST子目录下附加的样本代码中,找到相应的工程文件。全部18个动态链接库都是由相同的工程文件产生的;读者可以建立自己的动态链接库原始版本(未经调试的版本),然后使用以下的命名规则,将产生的可执行代码复制到新的位置。PTAPP样本应用程序要求在动态链接库的名字中,包含DLL内容信息。动态链接库名字的每一个字母代表一种属性,对应的命名规则如下:第一个字母代表动态链接库是小库(不包含任何数据)还是大库(包含100,000个静态数据元素)。此位置如果是S,表示动态链接库是小库;此位置如果是L,表示动态链接库是大库;F表

13、示所有的100,000个数据元素都初始化为可重定位的自串,当动态链接库进行基址重置时,字串的地址必须在加载时进行调整。注意:有100,000个可重定位的字串并不表示一定要进行100,000次重定位。对于Visual C+版本2.x来说,还存在一个问题,Visual C+的连接器将可移植的可执行文件中的可重定位项数目限制在64K之内。因此,如果在某个名字以F开始的动态链接库中,运行.EXE头实用程序,例如YAHU,用户会发现只有34K可重定位的地址。这一问题将在新版本的Visual C+中得到解决。第二个字母表示动态链接库是否支持CRT代码(C run-time)。如果此位为N,表示DLL有一个

14、自定义入口点,不调用CRT初始化代码(C run-time);如果此位为C,表示动态链接库的入口地址是DllMain,可以隐式地初始化CRT(C run-time);如果此位为D,表示动态链接库有一个自定义的入口地址,调用_CRT_INIT,动态地初始化CRT(C run-time)库。最后,第三个字母如果是N,表示动态链接库不输出任何符号;如果是E表示输出一个函数。其余的字母现在还未指定含义。例如,SCNNNNNN.DLL是一个小的动态链接库,隐式调用CRT(C run-time)初始化代码,但不输出任何符号。FNENNNNN.DLL是一个大的动态链接库,有许多重定位地址,不调用CRT(C

15、run-time)初始化代码,但输出一个符号。为了不将任何不需要的副作用引入比较过程中去,作者将动态链接库编写的尽可能的小。作者提供的最小的动态链接库,含有一些自定义的动态链接库入口点,不初始化CRT(C run-time)支持代码。在作者提供的任何动态链接库中,都不支持MFC。这主要因为MFC动态链接库隐式链接到其他动态链接库上,并执行作者不希望引入到测试程序中的自定义初始化过程。所有其他动态链接库的变量都是按照如下方式,通过对工程文件略作修改而得到的:为了将小的动态链接库制成大的动态链接库,需要将MANYPAGES符号加入到预处理器伪指令(preprocessor directive)中。

16、可以通过在预处理器定义中,加入MANYPAGES和FIXUPS,产生大的动态链接库,这种动态链接库中有很多修复地址。如果需要建立一个使用自定义入口指针,调用CRT(C run-time)初始化代码的动态链接库,可以加入DYNACRT符号;如果想建立一个具有隐式CRT初始化代码的动态链接库,可以加入STANDARDENTRY符号,并在Settings/Link/Entry文本框中,将动态链接库的入口指针指向DllMain。最后,如果需要动态链接库输出一个符号,可以加入预处理器伪指令HASSYMBOLS。作者还定义了一个名为HUGEBINARY的符号,用于产生真正的大动态链接库(即具有大约15,000个数据页的动态链接库,将此符号与FIXUPS符号连用,将产生大约15,000个重定位地址。)动态链接库的大小在40到61MB之间,具体大小取决于用户是否定义了FIXUPS。在测试实例中,作者没有在动态链接库测试集中加入二进制代码。无论用户选择哪一种选项来建立动态链接库,最终产生的可执行程序都会存储在PAGETEST工程的WINREL子目录下的PAGET

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 工作计划

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号