• Windows下的动态链接


    Windows下的动态链接

    DLL简介

    DLL的设计目的与共享对象有些出入,DLL更加强调模块化,即微软希望通过DLL机制加强软件的模块化设计,使得各种模块之间能够松散地组合、重用和升级。

    • 进程地址空间和内存管理:进程拥有独立的地址空间

    • 基地址(Base Address)和相对地址(RVA, Relative Virtual Address)

    • DLL共享数据段

    • 导出:__declspec(dllexport) 修饰

    • 导入:__declspec(dllexport) 修饰

    • 通过externel "C"修饰来使用C语言的符号修饰

    • 使用.def文件中的IMPORT和EXPORTS段来声明导入导出符号,好处是可以控制符号的符号名。

    • 导入库(Import Library):.lib文件用来描述导出符号,并不包含代码和数据。

    • DLL显式运行时链接

      • LoadLibrary:与dlopen类似

      • GetProcAddress:与dlsym类似

      • FreeLibrary:与dlclose类似

    符号导出导入表

    • 导出表

      • 导出地址表

      • 符号名表

      • 名字序号对应表

    • EXP文件:导出表的临时文件

    • 导出重定向:正常情况下,导出表的地址数组中包含的是函数的RVA,但是如果这个RVA指向的位置位于导出表中,那么表示这个符号被重定向了。它是指向一个ASCII的字符串,是符号重定向后的DLL文件名和符号名。

    • 导入表:Windows将会保证依赖关系的正确和所有的导入符号都被正确地解析,如果某个模块无法正确加载,系统将会提示错误,终止运行该程序。

    • 延迟载入

    • 导入函数的调用

    DLL优化

    • 重定基地址:不同于代码段地址无关,它采用的是装载时重定位的方法。

    • 序号

    • 导入函数绑定

    C++与动态链接

    使用C++编写共享库要复杂的多,并且难以更新。因为C++标准值规定了语言层面的规则,而对二进制级别却没有任何规定。为了解决类似的兼容性问题,微软公司很早就开始了组件对象模型(COM,Component object model)的开发工作

    • 所有的接口函数都应该是抽象的。所有的方法都应该是纯虚的。

    • 所有的全局函数都应该使用extern "C"来防止名字修饰的不兼容。并且导出函数的都应该是__stdcall调用规范的。这样即使用户本身的程序是默认以__cdecl方式编译的,对于DLL的调用也能够正确。

    • 不要使用C++标准库STL。

    • 不要使用异常

    • 不要使用虚析构函数。可以创建一个destroy()方法并且重载delete操作符并且调用destroy()。

    • 不要在DLL里面申请内存,而且在DLL外释放。不同的DLL和可执行文件可能使用不同的堆,在一个堆里面申请内存而在另外一个堆里面释放会导致错误。对于内存分配相关的函数不应该是inline的,以防止它在编译时被展开到不同的DLL和可执行文件。

    • 不要在接口中使用重载方法(一个方法多重参数)。因为不同的编译器对于vtable的安排可能不同。

    DLL HELL

    • 产生原因:

      • 使用旧版本的DLL替代原来一个新版本的DLL

      • 新版DLL中的函数无意发生改变

      • 新版DLL的安装引入一个新BUG

    • 解决方法:

      • 静态链接

      • 防止DLL覆盖:使用Windows文件保护(WFP)技术来缓解。它能阻止未经授权的应用程序覆盖系统的DLL。第三方应用程序不能覆盖操作系统DLL文件。

      • 避免DLL冲突:让每个应用程序拥有一份自己依赖的DLL,并且把问题DLL的不同版本放到该应用程序的文件夹中,而不是系统文件夹中。

      • .NET:Manifest文件描述程序集的名字,版本号以及各种资源,同时也描述了该程序集的运行所依赖的资源,包括DLL以及其他资源文件等。它是一个XML的描述文件,每个DLL和EXE都有自己的Manifest文件。

    小结

  • 相关阅读:
    14-6-27&28自学内容小结
    暑假要自学Java了
    找最大值算法(面试题)
    冒泡排序(面试题)
    循环
    运算符和表达式 、 分支结构 使用三目运算符的嵌套,比较a、b、c三个整数的大小并输出结果
    运算符和表达式 、 分支结构 输入年份和月份,输出该月的天数(使用switch-case)
    运算符和表达式 、 分支结构 3 个数值进行升序排列
    运算符和表达式 、 分支结构 例题 闰年判断
    变量 、 JAVA基本类型 3.3.5. 关于“短路逻辑”的问题
  • 原文地址:https://www.cnblogs.com/fr-ruiyang/p/14527909.html
Copyright © 2020-2023  润新知