原创 C++应用程序在Windows下的编译、链接(四)动态链接
4动态链接
4.1概述
在静态链接阶段,链接器为PE文件生成了导入表,导出表,符号表,并调整了Call指令后面的操作数,在程序调用的时候,能够直接地或者间接地定位到IAT中的某个位置,在PE文件中,该位置包含符号的名称,当PE文件加载到内存以后,该位置应该修正为符号的地址。这些已有的信息和已经完成的工作是后续动态链接的基础。
动态链接的任务是:在程序的加载或者运行阶段,执行各个模块的基址重定位工作,并将IAT中的符号名称修正为动态链接库中被调用的符号的地址。
动态链接分为隐式动态链接和显式动态链接,无论是隐式动态链接还是显式动态链接,都会涉及到对WindowsAPI函数:LoadLibrary(),GetProcAddress(),FreeLibrary()的调用。它们之间的区别是:在执行隐式动态链接的时候,由Windows加载器负责完成对这些Windows API的调用;而在显式动态链接的时候,这些Windows API函数必须由程序员编写代码主动地调用。
隐式动态链接在程序加载到内存的时候完成,而显式动态链接则将这一过程推迟到程序运行的过程中。
动态链接的流程如下图所示:
由上图可以看出,动态链接的两个主要任务:动态链接库加载完毕以后的基址重定位,以及对导入表中函数名称的修正,即:将函数名称转换成函数的地址。
4.2程序加载及基址重定位
PE文件具有段结构,包含的主要的段有:代码段,数据段,导入表,导出表,符号表,基址重定位表等。当PE文件存储在文件中或者被加载到内存中的时候,这些段都需要遵循某个对齐规则。
PE中规定了三类对齐:数据在内存中的对齐,数据在文件中的对齐,资源数据在资源文件中的对齐。
数据在内存中的对齐。在内存中,PE文件以内存页的大小作为对齐粒度。在Windows操作系统中,内存以分页的方式进行管理。在32位Windows下,内存页的大小是4KB;在64位Windows下,内存页的大小是8KB。当PE文件被加载到内存以后,各段的起始地址必须是内存页大小的整数倍。
数据在文件中的对齐。在文件中,PE文件以一个扇区的大小作为对齐粒度。一个扇区的大小为512字节,十六进制表示为200h。在文件存储中,各段的地址偏移必须是200h的整数倍。
资源数据在资源文件中的对齐。在资源文件中,资源字节码以4字节作为对齐粒度。
由于在内存中PE文件以4KB作为对齐粒度,而在文件中以512字节作为对齐粒度,因此当PE文件被加载到内存以后,PE文件的尺寸要大于该文件在硬盘上的尺寸。在执行加载的时候,操作系统会读取PE文件的头信息,去除不需要加载到内存的部分,如:调试信息等,然后操作系统将整个PE文件映射到内存空间中。在将PE文件加载到内存以后,PE文件的结构和布局不会被改变。因此,PE文件在硬盘上的数据结构与在内存中的数据结构是相同的。具体的对比情况如下图所示:
当PE文件被windows加载器加载到内存以后,在内存中的版本被称为模块,每一个模块的起始内存地址被称为HMODULE。通过这个HMODULE可以获得该模块的数据内容。
当可执行程序被加载到内存以后,Windows会查询PE文件中的相关信息,获得该可执行程序所依赖的动态链接库,然后Windows将这些动态链接库也加载到内存中。如果某个要被加载地动态链接库已经位于内存中,那么操作系统就增加这个动态链接库的引用计数。当可执行程序和它所依赖的动态链接库都被加载到内存以后,Windows加载器开始执行基址重定位工作。Windows加载器加载可执行程序以及动态链接库的流程如下图所示:
当可执行文件以及它所依赖的动态链接库文件被加载到内存以后,如果该文件被加载的内存位置不是基于默认内存地址的位置(可执行程序是0x00400000h,动态链接库是0x10000000),那么windows加载器就必须执行基址重定位工作。该工作是在基址重定位表的支持下完成的。对于每一个需要进行重定位的内存地址,加载器都会给它加上一个差值作为修正。该差值为模块当前加载到内存的地址 – 模块默认加载位置的地址。具体的操作流程如下图所示:
当完成基址重定位工作以后,导出地址表(EAT)中的地址也被修正完毕。在PE文件中,这些地址是基于默认加载位置的地址,如果当前加载位置发生了变化,那么这些地址是要被修正的。参见2.4.7节。
4.3符号解析
符号解析是动态链接中最重要的一环,在该阶段,加载器读取PE文件中的导入地址表(IAT)的信息,取得每一个函数的名称,然后用该函数的名称去相关动态链接库中查询函数的地址,用获得的地址替换该函数名称。这一步工作是将函数名称替换为函数地址的过程。具体过程如下图所示:
由于一个可执行程序可能会依赖多个动态链接库,那么在导入表数组中就会包含多个数组元素,所以在符号解析的时候是一个循环处理。加载器对导入表数组执行循环,取得每一个数组元素,然后根据获得的Dll名称查找到相关的动态链接库的位置。获得了相关动态链接库的信息以后,加载器从导入地址表中取得一个符号的名称,以该符号名称为条件去对应的动态链接库中查询。经过对符号名称表,名称序号对应表,以及符号地址表的查询,最后获得符号的地址,将此地址写回到导入地址表原来符号名称的位置。
嗯,那个恭喜你,看完了。为了写这个东西,也把我累的够呛,哈哈。
原创 C++应用程序在Windows下的编译、链接(四)动态链接的更多相关文章
- 原创 C++应用程序在Windows下的编译、链接:第一部分 概述
本文是对C++应用程序在Windows下的编译.链接的深入理解和分析,文章的目录如下: 我们先看第一章概述部分. 1概述 1.1编译工具简介 cl.exe是windows平台下的编译器,link.ex ...
- 原创 C++应用程序在Windows下的编译、链接:第三部分 静态链接(二)
3.5.2动态链接库的创建 3.5.2.1动态链接库的创建流程 动态链接库的创建流程如下图所示: 在系统设计阶段,主要的设计内容包括:类结构的设计以及功能类之间的关系,动态链接库的接口.在动态链接库中 ...
- 原创 C++应用程序在Windows下的编译、链接:第二部分COFF/PE文件结构
2.1概述 在windows操作系统下,可执行文件的存储格式是PE格式:在Linux操作系统下,可执行文件的存储格式的WLF格式.它们都是COFF格式文件的变种,都是从COFF格式的文件演化而来的. ...
- C++应用程序在Windows下的编译、链接(一)概述
C++应用程序在Windows下的编译.链接(一)概述 本文是对C++应用程序在Windows下的编译.链接的深入理解和分析,文章的目录如下: 我们先看第一章概述部分. 1概述 1.1编译工具简介 c ...
- QT程序在windows下部署发布
转载:http://www.cnblogs.com/Fan_Fan/archive/2010/05/29/1746860.html QT程序在windows下部署发布 以下包括了部分网上收集的,以及q ...
- 解析 Qt 程序在Windows 下发布
原文请看:http://www.cnblogs.com/elect-fans/archive/2012/03/15/2408579.html Qt 程序在Windows下发布是本文要介绍的内容,不多说 ...
- 【FFmpeg】Windows下FFmpeg编译
由于FFmpeg是基于Linux开发的开源项目,源代码和Windows下最常见的Visual Studio提供的C/C++编译器不兼容,因此它不能使用MSVC++编译,需要在Windows下配置一个类 ...
- boost库在windows下的编译和使用
因为跨平台的原因,现在要使用到boost库,boost库非常大,现在处于摸索阶段. 首先来说boost库在window下的安装和使用. 一.下载 首先从boost官方主页http://www.boos ...
- ACE在windows下的编译及配置(VS2010)
ACE在windows下的编译及配置(VS2010) 分类: -[小西南]- 2013-08-06 16:17 2354人阅读 评论( ...
随机推荐
- [ 技术人员创业Tips ] 1:抓住优质客户(上)
写一篇技术以外的内容,可能会得罪一些人,轻拍,此外本文写的比较随意,写到哪里算哪里,轻拍. IT业不知道从什么时候起特别流行谈创业,似乎不谈创业就落伍,我不评价这种风气的好坏,只提一些自己的一些经验和 ...
- Spark笔记:复杂RDD的API的理解(下)
本篇接着谈谈那些稍微复杂的API. 1) flatMapValues:针对Pair RDD中的每个值应用一个返回迭代器的函数,然后对返回的每个元素都生成一个对应原键的键值对记录 这个方法我最开始接 ...
- 一缕阳光:DDD(领域驱动设计)应对具体业务场景,如何聚焦 Domain Model(领域模型)?
写在前面 阅读目录: 问题根源是什么? <领域驱动设计-软件核心复杂性应对之道>分层概念 Repository(仓储)职责所在? Domain Model(领域模型)重新设计 Domain ...
- ABP框架 - 数据传输对象
文档目录 本节内容: DTO 必要性 领域层的抽象 数据隐藏 序列化和延迟加载问题 DTO 约定和验证 示例 DTO和实体间自动映射 使用特性和扩展方法进行映射 辅助接口和类 Data Transfe ...
- node之path模块
node之path模块 原文链接 //引用该模块 var path = require("path"); 1.路径解析,得到规范化的路径格式 对window系统,目录分隔为'', ...
- Underscore.js
概述 Underscore.js是一个很精干的库,压缩后只有4KB.它提供了几十种函数式编程的方法,弥补了标准库的不足,大大方便了JavaScript的编程.MVC框架Backbone.js就将这个库 ...
- 关于php语言的使用!
------php语言与JavaScript的使用 方法是相似 <script type="text/javascript"> </script>--js与 ...
- 为WLW开发Latex公式插件
WLW是写博客的利器,支持离线.格式排版等,而且拥有众多的插件.博客园推荐了代码插入插件,但是没有提供WLW的公式编译插件.目前我的一般做法是:先在Word下使用MathType编辑好公式,然后将公式 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统--工作流演示截图
- Restful 介绍及SpringMVC+restful 实例讲解
restful不是一个框架,称为一种编码更烦更贴切吧,其核心类位于spring-web.jar中,即RestTemplate.class restful是rpc通过http协议的一种实现方式,和web ...