Microsoft可移植可执行文件和通用目标文件格式文件规范

2020年02月09日 阅读数:396
这篇文章主要向大家介绍Microsoft可移植可执行文件和通用目标文件格式文件规范,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。
Microsoft 可移植可执行文件和通用目标文件格式文件规范
修订版8.1 - 2008年2月15日
摘要
本规范描述了Microsoft® Windows®操做系统家族下的可执行文件(映像)和目标文件的结构。这些文件分别被称为可移植可执行(PE)文件和通用目标文件格式(COFF)文件。
注意 :提供本文档是为了辅助开发用于Microsoft Windows操做系统上的工具和应用程序,但并不保证它在各个方面都是完整的规范。Microsoft保留更改本文档而不通知的权利。
 
Microsoft 可移植可执行文件和通用目标文件格式文件规范的这次修订版取代了本规范的6.0修订版。
本规范中的信息适用于如下操做系统:
    Windows Server
® 2008
    Windows Vista®
    Windows Server 2003
    Windows XP
    Windows 2000
本规范最后列出了参考信息和相关资源。
本规范的最新版在万维网的如下地址被维护:
http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
 
 
 
 
SmartTech译
电子信箱:zhzhtst@163.com
 
法律声明

Microsoft 可移植可执行文件和通用目标文件格式文件规范
Microsoft Corporation
修订版 8. 1
 
注意:提供本规范是为了辅助开发某些用于Microsoft Windows操做系统平台上的开发工具。可是Microsoft并不保证它在各个方面都是完整的规范,也没法保证这里的全部信息在发布以后一直都是准确的。Microsoft保留更改本规范而不通知的权利。
 
在合理的和非歧视性条款和条件下,Microsoft将针对任何Microsoft认为仅在面向Microsoft Windows的被称为编译器、连接器以及汇编程序的软件开发工具中实现和遵照本规范中所需部分这种有限用途下所须要的Microsoft权利要求书(若是存在)授予您免版税许可。
 
遵照全部适用的版 法是用 任。在不限制版权许可权利的前提下,未 Microsoft 明确 可,不得出于任何目的或以任何形式或任何手段( 子、机械、影印、 记录 或其余方法) 制本规范的任何部分,或者将其存 或引入 索系 ,或者修改或用于其衍生做品,或者将其 播。
 
于本规范中的主 Microsoft 可能拥有 识产权 。除非 可中明确 定,否 提供本规范并不意味着 Microsoft 经过暗示、默许或其它方式针对这 些知 识产权和其它权利 授予您 任何许可。
 
© 2005 -2008 Microsoft Corporation。保留全部权利。
 
本规范依“原样”提供。Microsoft不针对下列情形做任何明示的、暗示的或者法定的表示或担保:(1)本规范中的信息,包括对适销性、针对特定目的的适用性、不侵权或全部权的担保;(2)本规范中的内容适用于任何用途;(3)对这些内容的实现不会侵犯任何第三方的专利、版权、商标或其它权利。
 
Microsoft不就由本规范及其相关的使用或分发所带来的任何直接的、间接的、特别的、偶然的或者后果性的损害负任何责任。
 
Microsoft MS-DOS MSDN Visual Studio Visual C++ Win32 Windows Windows NT Windows Server Windows Vista 是Microsoft Corporation 在美国和/或其它国家的注册商标或商标。这里提到的其它产品和公司名称多是其各自全部者的商标。
 
于上述名称和商 ,在没有事先获得其各自全部者明确 可的状况下,不得以任何方式使用,包括广告或宣 范及其内容。
 
文档更新历史记录:
日期
更改
2/15/2008
更新了5.7节,并将附录A移到了“ Windows Authenticode 可移植可执行签名格式”中
5/18/2006
建立
 

目录
 
1基本概念
本文档详细说明了Microsoft® Windows®操做系统家族下的可执行文件(映像)和目标文件的结构。这些文件分别被称为可移植可执行(PE)文件和通用目标文件格式(COFF)文件。“可移植可执行”这个名称道出了这种格式与平台体系结构无关的事实。
下表描述了贯穿于本规范中的一些概念:
名称
描述
属性证书
用来将可校验的声明与映像关联起来的证书。有许多不一样的可校验声明能够与文件关联,最经常使用的一种就是软件制造商用来指明映像的消息摘要是什么的声明。消息摘要与校验和相似,但想要伪造它却极其困难。所以对一个文件进行修改并保持它的消息摘要与原始文件一致是很是困难的。正如制造商所作的那样,可使用公钥或私钥加密机制来校验声明。本文档除了描述容许将它们插入到映像文件中外还描述了有关属性证书的详细信息。
日期/时间戳
因为不一样目的而用于PE或COFF文件中好几个地方的戳。戳的格式与C运行时库时间函数所使用的戳的格式相同。
文件指针
某项内容在文件被连接器处理前(若是是目标文件文件)或者被加载器处理前(若是是映像文件)在文件自身中的位置。换句话说,这是一个位于存储在磁盘上的文件中的位置。
连接器
指的是随 Microsoft Visual Studio® 提供的连接器。
映像文件
可执行文件:或者是.EXE文件,或者是DLL。映像文件能够被认为是“内存映像”。术语“映像文件”常常用来代替“可执行文件”,由于后者有时仅用来指代.EXE文件。
目标文件
做为连接器的输入的文件。连接器生成一个映像文件,而这个映像文件又做为加载器的输入。
保留,必须为0
对一个域的这种描述代表,对于生成这个域的程序来讲必须将这个域设置为0,对于使用这个域的程序来讲必须忽略它的值。
RVA
相对虚拟地址。对于映像文件来讲,它是某项内容被加载进内存后的地址减去映像文件的基地址。某项内容的RVA几乎老是与它在磁盘上的文件中的位置(文件指针)不一样。
对于目标文件来讲,RVA并无什么意义,由于内存位置还没有分配。在这种状况下,RVA是一个节(后面将要描述)中的地址,这个地址在之后连接时要被重定位。为了简单起见,编译器应该将每一个节的首个RVA设置为0。
节是PE或COFF文件中代码或数据的基本单元。例如一个目标文件中全部代码能够被组合成单个节,或者(依赖于编译器的行为)每一个函数独占一个节。增长节的数目会增长文件开销,可是连接器在连接代码时有更大的选择余地。节与Intel 8086体系结构中的段很是类似。一个节中的全部原始数据必须被加载到连续的内存中。另外,映像文件可能包含一些具备特殊用途的节,例如.tls节或.reloc节。
VA
虚拟地址。除了不减去映像文件的基地址外,与RVA相同。这个地址之因此被叫作“虚拟地址”是由于Windows为每一个进程建立一个私有的虚拟地址空间,它独立于物理内存。不管出于何种目的,VA都只应该被认为是一个地址。VA并不能像RVA那样可以预先获得,由于加载器可能不把映像加载到它的首选位置上。
2概览
 
1 解释了Microsoft PE可执行文件格式:
MS-DOS 2.0 兼容
EXE 文件头
 
映像头基地址
未使用
 
 
OEM 标识
OEM 信息
 
PE文件头偏移
 
 
 
MS‑DOS 2.0
(仅用于MS­‑DOS兼容)
MS‑DOS 2.0 占位程序
 
重定位表
 
 
未使用
 
 
PE 文件头
(按8字节边界对齐)
 
 
 
节头
 
 
 
 
 
映像页:
导入信息
导出信息
基址重定位信息
资源信息
 
 
 
图 1.典型的可移植EXE文件布局
 
2 解释了Microsoft COFF目标模块格式:
Microsoft COFF文件头
 
 
 
 
节头
 
 
 
 
 
原始数据:
代码
数据
调试信息
重定位信息
 
 
 
图 2. 典型的COFF目标模块布局
3文件头
PE 文件头由Microsoft MS‑DOS®占位程序、PE文件签名、COFF文件头以及可选文件头组成,COFF目标文件头由COFF文件头和可选文件头组成。在这两种状况下,文件头后面紧跟着的都是节头。
3.1 MS‑DOS占位程序(仅适用于映像文件)
MS‑DOS 占位程序是一个运行于 MS‑DOS 下的合法应用程序,它被放在EXE映像的最前面。连接器在这里放一个默认的占位程序,当映像运行于MS‑DOS下时,这个占位程序显示“This program cannot be run in DOS mode(此程序不能在DOS模式下运行)” 这条消息。用户可使用 /STUB 连接器选项来指定一个不一样的占位程序。
在位置0x3C处,这个占位程序包含PE文件签名的偏移地址。此信息的存在使得即便映像文件中有一个MS‑DOS占位程序,Windows仍然可以正常执行它。这个文件偏移是在连接时被放在0x3C处的。
3.2签名(仅适用于映像文件)
在MS‑DOS占位程序后面、在偏移0x3C指定的文件偏移处,是一个4字节的签名,它用来标识文件为一个PE格式的映像文件。这个签名是“PE/0/0”(字母“P”和“E”后跟着两个空字节)。
3.3 COFF文件头(适用于目标文件和映像文件)
在目标文件的开头,或者紧跟着映像文件签名以后,是一个以下格式的标准COFF文件头。注意Windows加载器限制节的最大数目为96。
偏移
大小
描述
0
2
Machine
标识目标机器类型的数字。要获取更多信息,请参考3.3.1节“机器类型”。
2
2
NumberOfSections
节的数目。它给出了节表的大小,而节表紧跟着文件头。
4
4
TimeDateStamp
从UTC时间1970年1月1日00:00起的总秒数(一个C运行时time_t类型的值)的低32位,它指出文件什么时候被建立。
8
4
PointerToSymbolTable
COFF 符号表的文件偏移。若是不存在COFF符号表,此值为0。对于映像文件来讲,此值应该为0,由于已经不同意使用COFF调试信息了。
12
4
NumberOfSymbols
符号表中的元素数目。因为字符串表紧跟符号表,因此能够利用这个值来定位字符串表。对于映像文件来讲,此值应该为0,由于已经不同意使用COFF调试信息了。
16
2
SizeOfOptionalHeader
可选文件头的大小。可执行文件须要可选文件头而目标文件并不须要。对于目标文件来讲,此值应该为0。要获取可选文件头格式的详细描述,请参考3.4节“可选文件头(仅适用于映像文件)”。
18
2
Characteristics
指示文件属性的标志。对于特定的标志,请参考3.3.2节“特征”。
3.3.1机器类型
Machine 域能够取如下各值中的一个来指定CPU类型。 映像文件仅能运行于指定处理器或者可以模拟指定处理器的系统上。
常量
描述
IMAGE_FILE_MACHINE_UNKNOWN
0x0
适用于任何类型处理器
IMAGE_FILE_MACHINE_AM33
0x1d3
Matsushita AM33 处理器
IMAGE_FILE_MACHINE_AMD64
0x8664
x64 处理器
IMAGE_FILE_MACHINE_ARM
0x1c0
ARM 小尾处理器
IMAGE_FILE_MACHINE_EBC
0xebc
EFI 字节码处理器
IMAGE_FILE_MACHINE_I386
0x14c
Intel 386 或后继处理器及其兼容处理器
IMAGE_FILE_MACHINE_IA64
0x200
Intel Itanium 处理器家族
IMAGE_FILE_MACHINE_M32R
0x9041
Mitsubishi M32R 小尾处理器
IMAGE_FILE_MACHINE_MIPS16
0x266
MIPS16 处理器
IMAGE_FILE_MACHINE_MIPSFPU
0x366
FPU 的MIPS处理器
IMAGE_FILE_MACHINE_MIPSFPU16
0x466
FPU 的MIPS16处理器
IMAGE_FILE_MACHINE_POWERPC
0x1f0
PowerPC 小尾处理器
IMAGE_FILE_MACHINE_POWERPCFP
0x1f1
带符点运算支持的 PowerPC 处理器
IMAGE_FILE_MACHINE_R4000
0x166
MIPS 小尾处理器
IMAGE_FILE_MACHINE_SH3
0x1a2
Hitachi SH3 处理器
IMAGE_FILE_MACHINE_SH3DSP
0x1a3
Hitachi SH3 DSP 处理器
IMAGE_FILE_MACHINE_SH4
0x1a6
Hitachi SH4 处理器
IMAGE_FILE_MACHINE_SH5
0x1a8
Hitachi SH5 处理器
IMAGE_FILE_MACHINE_THUMB
0x1c2
Thumb 处理器
IMAGE_FILE_MACHINE_WCEMIPSV2
0x169
MIPS 小尾 WCE v2 处理器
3.3.2特征
Characteristics 域包含指示目标文件或映像文件属性的标志。当前定义了如下值:
标志
描述
IMAGE_FILE_RELOCS_STRIPPED
0x0001
仅适用于映像文件,适用于 Windows CE Microsoft Windows NT® 及其后继操做系统。它代表此文件不包含基址重定位信息,所以必须被加载到其首选基地址上。若是基地址不可用,加载器会报错。连接器默认会移除可执行(EXE)文件中的重定位信息。
IMAGE_FILE_EXECUTABLE_IMAGE
0x0002
仅适用于映像文件。它代表此映像文件是合法的,能够被运行。若是未设置此标志,代表出现了连接器错误。
IMAGE_FILE_LINE_NUMS_STRIPPED
0x0004
COFF 行号信息已经被移除。不同意使用此标志,它应该为0。
IMAGE_FILE_LOCAL_SYMS_STRIPPED
0x0008
COFF 符号表中有关局部符号的项已经被移除。不同意使用此标志,它应该为0。
IMAGE_FILE_AGGRESSIVE_WS_TRIM
0x0010
此标志已经被舍弃。它用于调整工做集。Windows 2000及其后继操做系统不同意使用此标志,它应该为0。
IMAGE_FILE_LARGE_ADDRESS_AWARE
0x0020
应用程序能够处理大于2GB的地址。
 
0x0040
此标志保留供未来使用。
IMAGE_FILE_BYTES_REVERSED_LO
0x0080
小尾:在内存中,最不重要位(LSB)在最重要位(MSB)前面。不同意使用此标志,它应该为0。
IMAGE_FILE_32BIT_MACHINE
0x0100
机器类型基于32位字体系结构。
IMAGE_FILE_DEBUG_STRIPPED
0x0200
调试信息已经今后映像文件中移除。
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
0x0400
若是此映像文件在可移动介质上,彻底加载它并把它复制到交换文件中。
IMAGE_FILE_NET_RUN_FROM_SWAP
0x0800
若是此映像文件在网络介质上,彻底加载它并把它复制到交换文件中。
IMAGE_FILE_SYSTEM
0x1000
此映像文件是系统文件,而不是用户程序。
IMAGE_FILE_DLL
0x2000
此映像文件是动态连接库(DLL)。这样的文件总被认为是可执行文件,尽管它们并不能直接被运行。
IMAGE_FILE_UP_SYSTEM_ONLY
0x4000
此文件只能运行于单处理器机器上。
IMAGE_FILE_BYTES_REVERSED_HI
0x8000
大尾:在内存中,MSB在LSB前面。不同意使用此标志,它应该为0。
3.4可选文件头(仅适用于映像文件)
每一个映像文件都有一个可选文件头,用于为加载器提供信息。这个文件头之因此说是可选的是从一些文件(明确地说是目标文件)并不包含它这层意义上来讲的。对于映像文件来讲,这个文件头是必须的。目标文件能够包含一个可选文件头,可是一般它除了增长文件的大小外并没有其它做用。
注意可选文件头的大小并不固定。COFF文件头中的SizeOfOptionalHeader域用来验证某个特别的数据目录不超过SizeOfOptionalHeader。要获取更多信息,请参考3.3节“COFF文件头(适用于目标文件和映像文件)”
可选文件头中的NumberOfRvaAndSizes域也应该被用来确保某个特别的数据目录不超出可选文件头。另外出于格式兼容目的而去校验可选文件头中的幻数也很重要。
可选文件头中的幻数决定一个映像是PE32仍是PE32+格式的可执行文件:
幻数
PE 格式
0x10b
PE32
0x20b
PE32+
 
PE32+ 映像在限制映像大小最大为2G时能够访问64位地址空间。PE32+的其它更改在它们各自的节中描述。
可选文件头自身由三个主要部分组成:
偏移( PE32/PE32+
大小 PE32/PE32+
文件头部分
描述
0
28/24
标准域
这些域被全部COFF实现所定义,其中包括UNIX。
28/24
68/88
Windows 特定域
支持Windows特性(例如子系统)的附加域。
96/112
Variable
数据目录
映像文件中的特殊表(例如导入表和导出表)的地址/大小组合,它们供操做系统使用。
3.4.1可选文件头中的标准域(仅适用于映像文件)
可选文件头的前8个域为标准域,它们被全部COFF实现所定义。这些域包含对加载和运行可执行文件有用的常规信息。它们在PE32+中并未改变。
偏移
大小
描述
0
2
Magic
这个无符号整数指出了映像文件的状态。最经常使用的数字是0x10B,它代表这是一个正常的可执行文件。0x107代表这是一个ROM映像,0x20B代表这是一个PE32+可执行文件。
2
1
MajorLinkerVersion
连接器的主版本号。
3
1
MinorLinkerVersion
连接器的次版本号。
4
4
SizeOfCode
代码节(.text)的大小。若是有多个代码节的话,它是全部代码节的和。
8
4
SizeOfInitializedData
已初始化数据节的大小。若是有多个这样的数据节的话,它是全部这些数据节的和。
12
4
SizeOfUninitializedData
未初始化数据节(.bss)的大小。若是有多个.bss节的话,它是全部这些节的和。
16
4
AddressOfEntryPoint
当可执行文件被加载进内存时其入口点相对于映像基址的偏移地址。对于通常程序映像来讲,它就是启动地址。对于设备驱动程序来讲,它是初始化函数的地址。入口点对于DLL来讲是可选的。若是不存在入口点的话,这个域必须为0。
20
4
BaseOfCode
当映像被加载进内存时代码节的开头相对于映像基址的偏移地址。
 
PE32 中在 BaseOfCode 域后面是下面这个附加域,它并不存在于PE32+中:
偏移
大小
描述
24
4
BaseOfData
当映像被加载进内存时数据节的开头相对于映像基址的偏移地址。
3.4.2可选文件头中的Windows特定域(仅适用于映像文件)
接下来的21个域是COFF可选文件头格式的扩展。它们包含Windows中的连接器和加载器所必需的附加信息。
偏移 PE32/
PE32+
大小 PE32/
PE32+
描述
28/24
4/8
ImageBase
当加载进内存时映像的第一个字节的首选地址。它必须是64K的倍数。DLL默认是0x10000000。Windows CE EXE默认是0x00010000。Windows NT、Windows 2000、Windows XP、 Windows 9五、Windows 98和 Windows Me 默认是0x00400000。
32/32
4
SectionAlignment
当加载进内存时节的对齐值(以字节计)。它必须大于或等于 FileAlignment 。默认是相应系统的页面大小。
36/36
4
FileAlignment
用来对齐映像文件的节中的原始数据的对齐因子(以字节计)。它应该是界于512和64K之间的2的幂(包括这两个边界值)。默认是512。若是SectionAlignment小于相应系统的页面大小,那么FileAlignment必须与SectionAlignment匹配。
40/40
2
MajorOperatingSystemVersion
所需操做系统的主版本号。
42/42
2
MinorOperatingSystemVersion
所需操做系统的次版本号。
44/44
2
MajorImageVersion
映像的主版本号。
46/46
2
MinorImageVersion
映像的次版本号。
48/48
2
MajorSubsystemVersion
子系统的主版本号。
50/50
2
MinorSubsystemVersion
子系统的次版本号。
52/52
4
Win32VersionValue
保留,必须为0。
56/56
4
SizeOfImage
当映像被加载进内存时的大小(以字节计),包括全部的文件头。它必须是 SectionAlignment 的倍数。
60/60
4
SizeOfHeaders
MS‑DOS 占位程序、PE文件头和节头的总大小,向上舍入为 FileAlignment 的倍数。
64/64
4
CheckSum
映像文件的校验和。计算校验和的算法被合并到了IMAGEHLP.DLL 中。如下程序在加载时被校验以肯定其是否合法:全部的驱动程序、任何在引导时被加载的DLL以及加载进关键Windows进程中的DLL。
68/68
2
Subsystem
运行此映像所需的子系统。要获取更多信息,请参考后面的“Windows子系统”部分。
70/70
2
DllCharacteristics
要获取更多信息,请参考后面的“DLL特征”部分。
72/72
4/8
SizeOfStackReserve
保留的堆栈大小。只有 SizeOfStackCommit 指定的部分被提交;其他的每次可用一页,直到到达保留的大小为止。
76/80
4/8
SizeOfStackCommit
提交的堆栈大小。
80/88
4/8
SizeOfHeapReserve
保留的局部堆空间大小。只有 SizeOfHeapCommit 指定的部分被提交;其他的每次可用一页,直到到达保留的大小为止。
84/96
4/8
SizeOfHeapCommit
提交的局部堆空间大小。
88/104
4
LoaderFlags
保留,必须为0。
92/108
4
NumberOfRvaAndSizes
可选文件头其他部分中数据目录项的个数。每一个数据目录描述了一个表的位置和大小。
Windows子系统
为可选文件头的 Subsystem 域定义了如下值以肯定运行映像所需的Windows子系统(若是存在):
常量
描述
IMAGE_SUBSYSTEM_UNKNOWN
0
未知子系统
IMAGE_SUBSYSTEM_NATIVE
1
设备驱动程序和N ative Windows 进程
IMAGE_SUBSYSTEM_WINDOWS_GUI
2
Windows 图形用户界面( GUI )子系统
IMAGE_SUBSYSTEM_WINDOWS_CUI
3
Windows 字符模式(CUI)子系统
IMAGE_SUBSYSTEM_POSIX_CUI
7
Posix 字符模式子系统
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
9
Windows CE
IMAGE_SUBSYSTEM_EFI_APPLICATION
10
可扩展固件接口(EFI)应用程序
IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
11
带引导服务的 EFI 驱动程序
IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
12
带运行时服务的 EFI 驱动程序
IMAGE_SUBSYSTEM_EFI_ROM
13
EFI ROM 映像
IMAGE_SUBSYSTEM_XBOX
14
XBOX
DLL特征
为可选文件头的 DllCharacteristics 域定义了如下值:
常量
描述
 
0x0001
保留,必须为0。
 
0x0002
保留,必须为0。
 
0x0004
保留,必须为0。
 
0x0008
保留,必须为0。
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
0x0040
DLL 能够在加载时被重定位。
IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY
0x0080
强制进行代码完整性校验。
IMAGE_DLLCHARACTERISTICS_NX_COMPAT
0x0100
映像兼容于 NX
IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
0x0200
能够隔离,但并不隔离此映像。
IMAGE_DLLCHARACTERISTICS_NO_SEH
0x0400
不使用结构化异常(SE)处理。在此映像中不能调用SE处理程序。
IMAGE_DLLCHARACTERISTICS_NO_BIND
0x0800
不绑定映像。
 
0x1000
保留,必须为0。
IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
0x2000
WDM 驱动程序。
IMAGE_DLLCHARACTERISTICS_
TERMINAL_SERVER_AWARE
0x8000
能够用于终端服务器。
3.4.3可选文件头中的数据目录(仅适用于映像文件)
每一个数据目录给出了Windows使用的表或字符串的地址和大小。这些数据目录项所有被被加载进内存以备系统运行时使用。数据目录是按照以下格式定义的一个8字节结构:
typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
 
第一个域——VirtualAddress,其实是表的RVA。这个RVA是当表被加载进内存时相对于映像基地址的偏移地址。第二个域给出了表的大小(以字节计)。数据目录组成了可选文件头的最后一部分,它被列于下表中。
注意目录的数目是不固定的。在查看一个特定的目录以前,先检查可选文件头中的NumberOfRvaAndSizes域。
一样,不要想固然地认为在这个表中的RVA指向节的开头,或者认为包含特定表的节有特定的名字。
偏移
PE/PE32+
大小
描述
96/112
8
Export Table
导出表的地址和大小。要获取更多信息,请参考6.3节“.edata节(仅适用于映像文件)”。
104/120
8
Import Table
导入表的地址和大小。要获取更多信息,请参考6.4节“.idata节”。
112/128
8
Resource Table
资源表的地址和大小。要获取更多信息,请参考6.9节“.rsrc节”。
120/136
8
Exception Table
异常表的地址和大小。要获取更多信息,请参考6.5节“.pdata节”。
128/144
8
Certificate Table
属性证书表的地址和大小。要获取更多信息,请参考5.7节“属性证书表(仅适用于映像文件)”
136/152
8
Base Relocation Table
基址重定位表的地址和大小。要获取更多信息,请参考6.6节“.reloc节(仅适用于映像文件)”。
144/160
8
Debug
调试数据起始地址和大小。要获取更多信息,请参考6.1节“.debug节”。
152/168
8
Architecture
保留,必须为0。
160/176
8
Global Ptr
将被存储在全局指针寄存器中的一个值的RVA。这个结构的Size域必须为0。
168/184
8
TLS Table
线程局部存储(TLS)表的地址和大小。要获取更多信息,请参考6.7节“.tls节”。
176/192
8
Load Config Table
加载配置表的地址和大小。要获取更多信息,请参考6.8节“加载配置结构(仅适用于映像文件)”。
184/200
8
Bound Import
绑定导入表的地址和大小。
192/208
8
IAT
导入地址表的地址和大小。要获取更多信息,请参考6.4.4节“导入地址表”。
200/216
8
Delay Import Descriptor
延迟导入描述符的地址和大小。要获取更多信息,请参考5.8节“延迟加载导入表(仅适用于映像文件)”。
208/224
8
CLR Runtime Header
CLR 运行时头部的地址和大小。要获取更多信息,请参考6.10节“.cormeta节(仅适用于目标文件)”
216/232
8
保留,必须为0。
 
Certificate Table 域指向属性证书表。这些证书并不做为映像的一部分被加载进内存。此时它的第一个域是一个文件指针,而不是一般的RVA。
4节表(节头)
节表的每一行等效于一个节头。这个表紧跟可选文件头(若是存在的话)。之因此必须在这个位置是由于文件头中并无一个直接指向节表的指针,节表的位置是经过计算文件头后的第一个字节的位置来获得的。必定要确保使用文件头中指定的可选文件头的大小(来进行计算)。
节表中的元素数目由文件头中的NumberOfSections域给出。而元素的编号是从1开始的。表示代码节和数据节的元素的顺序由连接器决定。
在映像文件中,每一个节的VA值必须由连接器决定。这样可以保证这些节位置相邻且按升序排列,而且这些VA值必须是可选文件头中SectionAlignment域的倍数。
每一个节头(节表项)格式以下,共40个字节:
偏移
大小
描述
0
8
Name
这是一个8字节的UTF-8编码的字符串,不足8字节时用NULL填充。若是它正好是8字节,那就没有最后的NULL字符。若是名称更长的话,这个域中是一个斜杠(/)后跟一个用ASCII码表示的十进制数,这个十进制数表示字符串表中的偏移。可执行映像不使用字符串表也不支持长度超过8字节的节名。若是目标文件中有长节名的节最后要出如今可执行文件中,那么相应的长节名会被截断。
8
4
VirtualSize
当加载进内存时这个节的总大小。若是此值比SizeOfRawData大,那么多出的部分用0填充。这个域仅对可执行映像是合法的,对于目标文件来讲,它应该为0。
12
4
VirtualAddress
对于可执行映像来讲,这个域的值是这个节被加载进内存以后它的第一个字节相对于映像基址的偏移地址。对于目标文件来讲,这个域的值是没有重定位以前其第一个字节的地址;为了简单起见,编译器应该把此值设置为0。不然这个值是个任意值,可是在重定位时应该从偏移地址中减去这个值。
16
4
SizeOfRawData
(对于目标文件来讲)节的大小或者(对于映像文件来讲)磁盘文件中已初始化数据的大小。对于可执行映像来讲,它必须是可选文件头中FileAlignment域的倍数。若是它小于VirtualSize域的值,余下的部分用0填充。因为SizeOfRawData域要向上舍入,可是VirtualSize域并不舍入,所以可能出现SizeOfRawData域大于VirtualSize域的状况。当节中仅包含未初始化的数据时,这个域应该为0。
20
4
PointerToRawData
指向COFF文件中节的第一个页面的文件指针。对于可执行映像来讲,它必须是可选文件头中FileAlignment域的倍数。对于目标文件来讲,要得到最好的性能,此值应该按4字节边界对齐。当节中仅包含未初始化的数据时,这个域应该为0。
24
4
PointerToRelocations
指向节中重定位项开头的文件指针。对于可执行文件或者没有重定位项的文件来讲,此值应该为0。
28
4
PointerToLinenumbers
指向节中行号项开头的文件指针。若是没有COFF行号信息的话,此值应该为0。对于映像来讲,此值应该为0,由于已经不同意使用COFF调试信息了。
32
2
NumberOfRelocations
节中重定位项的个数。对于可执行映像来讲,此值应该为0。
34
2
NumberOfLinenumbers
节中行号项的个数。对于映像来讲,此值应该为0,由于已经不同意使用COFF调试信息了。
36
4
Characteristics
描述节特征的标志。要获取更多信息,请参考4.1节“节标志”。
4.1节标志
节头中的 Characteristics 域中的节标志指出了节的属性。
标志
描述
 
0x00000000
保留供未来使用。
 
0x00000001
保留供未来使用。
 
0x00000002
保留供未来使用。
 
0x00000004
保留供未来使用。
IMAGE_SCN_TYPE_NO_PAD
0x00000008
从这个节结尾到下一个边界之间不能填充。此标志被舍弃,它已经被IMAGE_SCN_ALIGN_1BYTES标志取代。此标志仅对目标文件合法。
 
0x00000010
保留供未来使用。
IMAGE_SCN_CNT_CODE
0x00000020
此节包含可执行代码。
IMAGE_SCN_C NT_INITIALIZED_DATA
0x00000040
此节包含已初始化的数据。
IMAGE_SCN_CNT_UNINITIALIZED_DATA
0x00000080
此节包含未初始化的数据。
IMAGE_SCN_LNK_OTHER
0x00000100
保留供未来使用。
IMAGE_SCN_LNK_INFO
0x00000200
此节包含注释或者其它信息。.drectve 节具备这种属性。 此标志仅对目标文件合法。
 
0x00000400
保留供未来使用。
IMAGE_SCN_LNK_REMOVE
0x00000800
此节不会成为最终造成的映像文件的一部分。此标志仅对目标文件合法。
IMAGE_SCN_LNK_COMDAT
0x00001000
此节包含COMDAT数据。要获取更多信息,请参考5.5.6节“COMDAT 节(仅适用于目标文件) ”。此标志仅对目标文件合法。
IMAGE_SCN_GPREL
0x00008000
此节包含经过全局指针(GP)来引用的数据。
IMAGE_SCN_MEM_PURGEABLE
0x00020000
保留供未来使用。
IMAGE_SCN_MEM_16BIT
0x00020000
保留供未来使用。
IMAGE_SCN_MEM_LOCKED
0x00040000
保留供未来使用。
IMAGE_SCN_MEM_PRELOAD
0x00080000
保留供未来使用。
IMAGE_SCN_ALIGN_1BYTES
0x00100000
按1字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_2BYTES
0x00200000
按2字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_4BYTES
0x00300000
按4字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_8BYTES
0x00400000
按8字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_16BYTES
0x00500000
按16字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_32BYTES
0x00600000
按32字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_64BYTES
0x00700000
按64字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_128BYTES
0x00800000
按128字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_256BYTES
0x00900000
按256字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_512BYTES
0x00A00000
按512字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_1024BYTES
0x00B00000
按1024字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_2048BYTES
0x00C00000
按2048字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_4096BYTES
0x00D00000
按4096字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_ALIGN_8192BYTES
0x00E00000
按8192字节边界对齐数据。此标志仅对目标文件合法。
IMAGE_SCN_LNK_NRELOC_OVFL
0x01000000
此节包含扩展的重定位信息。
IMAGE_SCN_MEM_DISCARDABLE
0x02000000
此节能够在须要时被丢弃。
IMAGE_SCN_MEM_NOT_CACHED
0x04000000
此节不能被缓存。
IMAGE_SCN_MEM_NOT_PAGED
0x08000000
此节不能被交换到页面文件中。
IMAGE_SCN_MEM_SHARED
0x10000000
此节能够在内存中共享。
IMAGE_SCN_MEM_EXECUTE
0x20000000
此节能够做为代码执行。
IMAGE_SCN_MEM_READ
0x40000000
此节可读。
IMAGE_SCN_MEM_WRITE
0x80000000
此节可写。
 
IMAGE_SCN_LNK_NRELOC_OVFL 标志代表节中重定位项的个数超出了节头中为每一个节保留的16位所能表示的范围。若是设置了此标志而且节头中的NumberOfRelocations域的值是0xffff,那么实际的重定位项个数被保存在第一个重定位项的VirtualAddress域(32位)中。若是设置了IMAGE_SCN_LNK_NRELOC_OVFL标志但节中的重定位项的个数少于0xffff,则表示出现了错误。
4.2成组的节(仅适用于目标文件)
目标文件节名中的“$”字符(美圆符号)有特殊含义。
当由目标文件节中的内容生成映像文件的节时,连接器丢弃节名中“$”以及它后面的全部字符。所以目标文件中一个名为.text$X的节实际上成了映像文件中.text节的一部分。
可是“$”后面的字符决定了这些节在映像文件中的顺序。目标文件中节名(指的是节名中“$”字符之前的部分)相同的节被放在映像文件中连续的位置上,而且它们按节名的字母顺序排列。所以目标文件中节名为.text$X的节中的内容被放在一块儿,而且它们在名为.text$W节的内容以后,而在名为.text$Y节的内容以前。
映像文件节名中永远不会包含“$”字符。
5文件中的其它内容
到目前为止咱们所描述的结构,直到可选文件头(含),都位于从文件开头算起的固定偏移处(若是是包含MS‑DOS占位程序的映像文件的话则是从PE文件头开始算起)。
COFF 目标文件或映像文件中其他部分包含了那些并不须要处于某一特定文件偏移处的数据块。它们的位置由可选文件头或节头中相应的指针给出。
对于SectionAlignment值小于平台页面大小(Intel x86和MIPS是4K,Itanium是8K)的映像文件来讲有一个例外。要获取关于SectionAlignment的详细描述,请参考3.4节“可选文件头(仅适用于映像文件)”。此时节中数据的文件偏移有一些限制。详细信息请参考5.1节“节中的数据”。另一个例外状况是,属性证书和调试信息必须被放在映像文件的最后,而且属性证书表在调试信息节以前,这是由于加载器并不将这些信息映射进内存。可是对于属性证书和调试信息的这些限制并不适用于目标文件。
5.1节中的数据
节中已初始化的数据就是简单的字节块。可是对于那些仅包含0的节来讲,节中的数据就没有必要包含到文件中。
每一个节中的数据都位于节头的PointerToRawData域指定的文件偏移处。数据的大小由SizeOfRawData域给出。若是SizeOfRawData小于VirtualSize,那么余下的部分用0填充。
在映像文件中,节中的数据必须按可选文件头的FileAlignment域指定的边界对齐。节中的数据必须按相应节的RVA值的大小顺序出如今文件中(节表中单个的节头也是如此)。
若是可选文件头的SectionAlignment域的值小于相应平台的页面大小,那么映像文件有一些附加的限制。对于这种文件,当映像被加载到内存中时,节中数据在文件中的位置必须与它在内存中的位置匹配,所以节中数据的物理偏移与RVA相同。
5.2 COFF重定位信息(仅适用于目标文件)
目标文件中包含COFF重定位信息,它用来指出当节中的数据被放进映像文件以及未来被加载进内存时应如何修改这些数据。
映像文件中并不包含COFF重定位信息,这是由于全部被引用的符号都已经被赋予了一个在平坦内存空间中的地址。映像文件中包含的重定位信息是位于.reloc节中的基址重定位信息(除非映像具备IMAGE_FILE_RELOCS_STRIPPED属性)。要获取更多信息,请参考6.6节“.reloc节(仅适用于映像文件) ”。
对于目标文件中的每一个节,都有一个由长度固定的记录组成的数组来保存此节的COFF重定位信息。此数组的位置和长度在节头中指定。数组的每一个元素格式以下:
偏移
大小
描述
0
4
VirtualAddress
须要进行重定位的代码或数据的地址。这是从节开头算起的偏移,加上节的RVA/Offset域的值。请参考4节“节表(节头)”。例如若是节的第一个字节的地址是0x10,那么第三个字节的地址就是0x12。
4
4
SymbolTableIndex
符号表的索引(从0开始)。这个符号给出了用于重定位的地址。若是这个指定符号的存储类别为节,那么它的地址就是第一个与它同名的节的地址。
8
2
Type
重定位类型。合法的重定位类型依赖于机器类型。请参考5.2.1节“类型指示符”
 
若是SymbolTableIndex域指定的符号存储类别为IMAGE_SYM_CLASS_SECTION,那么这个符号的地址就是节的地址。这个节一般就在同一个文件中,除非这个目标文件是档案(库)文件的一部分。若是是这种状况的话,那么这个节可能位于档案文件中与当前目标文件的档案文件成员名称相同的任何其它目标文件中。(与档案文件成员名称的联系用于连接生成导入表,即.idata 节。
5.2.1类型指示符
重定位记录的Type域指出了重定位类型。对于每种类型的机器都定义了不一样的重定位类型。
x64处理器
为x64及其兼容处理器定义了如下重定位类型指示符:
常量
描述
IMAGE_REL_AMD64_ABSOLUTE
0x0000
重定位被忽略。
IMAGE_REL_AMD64_ADDR64
0x0001
重定位目标的64位VA。
IMAGE_REL_AMD64_ADDR32
0x0002
重定位目标的32位VA。
IMAGE_REL_AMD64_ADDR32NB
0x0003
不包含映像基址的32位地址(RVA)。
IMAGE_REL_AMD64_REL32
0x0004
相对于重定位目标的32位地址。
IMAGE_REL_AMD64_REL32_1
0x0005
相对于距重定位目标1字节处的32位地址。
IMAGE_REL_AMD64_REL32_2
0x0006
相对于距重定位目标2字节处的32位地址。
IMAGE_REL_AMD64_REL32_3
0x0007
相对于距重定位目标3字节处的32位地址。
IMAGE_REL_AMD64_REL32_4
0x0008
相对于距重定位目标4字节处的32位地址。
IMAGE_REL_AMD64_REL32_5
0x0009
相对于距重定位目标5字节处的32位地址。
IMAGE_REL_AMD64_SECTION
0x000A
包含重定位目标的节的16位索引。用于支持调试信息。
IMAGE_REL_AMD64_SECREL
0x000B
重定位目标相对于它所在节开头的32位偏移。用于支持调试信息和 静态线程局部存储。
IMAGE_REL_AMD64_SECREL7
0x000C
相对于重定位目标所在节基地址的7位偏移(无符号数)。
IMAGE_REL_AMD64_TOKEN
0x000D
CLR 记号。
IMAGE_REL_AMD64_SREL32
0x000E
放入目标文件中的32位跨度依赖值(符号数)。
IMAGE_REL_AMD64_PAIR
0x000F
与跨度依赖值成对出现,它必须紧跟每个跨度依赖值。
IMAGE_REL_AMD64_SSPAN32
0x0010
连接时应用的32位跨度依赖值(符号数)。
ARM处理器
为ARM处理器定义了如下重定位类型指示符:
常量
描述
IMAGE_REL_ARM_ABSOLUTE
0x0000
重定位被忽略。
IMAGE_REL_ARM_ADDR32
0x0001
重定位目标的32位VA。
IMAGE_REL_ARM_ADDR32NB
0x0002
重定位目标的32位RVA。
IMAGE_REL_ARM_BRANCH24
0x0003
重定位目标的24位相对偏移。
IMAGE_REL_ARM_BRANCH11
0x0004
对子程序调用的引用。这个引用由两个16位指令与11位偏移组成。
IMAGE_REL_ARM_SECTION
0x000E
包含重定位目标的节的16位索引。用于支持调试信息。
IMAGE_REL_ARM_SECREL
0x000F
重定位目标相对于它所在节开头的32位偏移。用于支持调试信息和 静态线程局部存储。
Hitachi SuperH处理器
为SH3和SH4处理器定义了如下重定位类型指示符。专用于SH5处理器的重定位类型都标有“SHM”字样,SHM表明SHMedia。
常量
描述
IMAGE_REL_SH3_ABSOLUTE
0x0000
重定位被忽略。
IMAGE_REL_SH3_DIRECT16
0x0001
对包含重定位目标符号VA的16位单元的引用。
IMAGE_REL_SH3_DIRECT32
0x0002
重定位目标符号的32位VA。
IMAGE_REL_SH3_DIRECT8
0x0003
对包含重定位目标符号VA的8位单元的引用。
IMAGE_REL_SH3_DIRECT8_WORD
0x0004
对包含重定位目标符号16位有效VA的8位指令的引用。
IMAGE_REL_SH3_DIRECT8_LONG
0x0005
对包含重定位目标符号32位有效VA的8位指令的引用。
IMAGE_REL_SH3_DIRECT4
0x0006
对其低4位包含重定位目标符号VA的8位单元的引用。
IMAGE_REL_SH3_DIRECT4_WORD
0x0007
对其低4位包含重定位目标符号16位有效VA的8位指令的引用。
IMAGE_REL_SH3_DIRECT4_LONG
0x0008
对其低4位包含重定位目标符号32位有效VA的8位指令的引用。
IMAGE_REL_SH3_PCREL8_WORD
0x0009
对包含重定位目标符号16位有效相对偏移的8位指令的引用。
IMAGE_REL_SH3_PCREL8_LONG
0x000A
对包含重定位目标符号32位有效相对偏移的8位指令的引用。
IMAGE_REL_SH3_PCREL12_WORD
0x000B
对其低12位包含重定位目标符号16位有效相对偏移的16位指令的引用。
IMAGE_REL_SH3_STARTOF_SECTION
0x000C
对包含重定位目标符号所在节VA的32位单元的引用。
IMAGE_REL_SH3_SIZEOF_SECTION
0x000D
对包含重定位目标符号所在节大小的32位单元的引用。
IMAGE_REL_SH3_SECTION
0x000E
包含重定位目标的节的16位索引。用于支持调试信息。
IMAGE_REL_SH3_SECREL
0x000F
重定位目标相对于它所在节开头的32位偏移。用于支持调试信息和 静态线程局部存储。
IMAGE_REL_SH3_DIRECT32_NB
0x0010
重定位目标符号的32位RVA。
IMAGE_REL_SH3_GPREL4_LONG
0x0011
GP 相关。
IMAGE_REL_SH3_TOKEN
0x0012
CLR 记号。
IMAGE_REL_SHM_PCRELPT
0x0013
距当前指令的偏移(长字)。若是没有设置IMAGE_REL_SHM_NOMODE标志,那么将低位取反插入到第32位以选择PTA指令或PTB指令。
IMAGE_REL_SHM_REFLO
0x0014
32 位地址的低16位。
IMAGE_REL_SHM_REFHALF
0x0015
32 位地址的高16位。
IMAGE_REL_SHM_RELLO
0x0016
相对地址的低16位。
IMAGE_REL_SHM_RELHALF
0x0017
相对地址的高16位。
IMAGE_REL_SHM_PAIR
0x0018
只有紧跟 IMAGE_REL_SHM_ REFHALF IMAGE_REL_SHM_ RELLO IMAGE_REL_SHM_ RELHALF 类型的重定位项时这种重定位类型才是合法的。此重定位项的SymbolTableIndex域包含的是偏移而不是符号表的索引。
IMAGE_REL_SHM_NOMODE
0x8000
重定位忽略节模式。
IBM PowerPC处理器
为PowerPC处理器定义了如下重定位类型指示符:
常量
描述
IMAGE_REL_PPC_ABSOLUTE
0x0000
重定位被忽略。
IMAGE_REL_PPC_ADDR64
0x0001
重定位目标的64位VA。
IMAGE_REL_PPC_ADDR32
0x0002
重定位目标的32位VA。
IMAGE_REL_PPC_ADDR24
0x0003
重定位目标VA的低24位。只有当重定位目标符号是绝对符号且能够按符号扩展到它的原始值时才是合法的。
IMAGE_REL_PPC_ADDR16
0x0004
重定位目标VA的低16位。
IMAGE_REL_PPC_ADDR14
0x0005
重定位目标VA的低14位。只有当重定位目标符号是绝对符号且能够按符号扩展到它的原始值时才是合法的。
IMAGE_REL_PPC_REL24
0x0006
符号位置相对于PC的24位偏移。
IMAGE_REL_PPC_REL14
0x0007
符号位置相对于PC的14位偏移。
IMAGE_REL_PPC_ADDR32NB
0x000A
重定位目标的32位RVA。
IMAGE_REL_PPC_SECREL
0x000B
重定位目标相对于它所在节开头的32位偏移。用于支持调试信息和 静态线程局部存储。
IMAGE_REL_PPC_SECTION
0x000C
包含重定位目标的节的16位索引。用于支持调试信息。
IMAGE_REL_PPC_SECREL16
0x000F
重定位目标相对于它所在节开头的16位偏移。用于支持调试信息和 静态线程局部存储。
IMAGE_REL_PPC_REFHI
0x0010
重定位目标32位VA的高16位。它用于加载一个完整地址所需的两指令序列中的第一条指令。这种重定位类型后面必须紧跟IMAGE_REL_PPC_PAIR类型的重定位项,然后者的SymbolTableIndex域包含的是一个16位偏移(符号数),这个偏移要被加到重定位目标位置的高16位。
IMAGE_REL_PPC_REFLO
0x0011
重定位目标VA的低16位。
IMAGE_REL_PPC_PAIR
0x0012
只有紧跟 IMAGE_REL_PPC_REFHI IMAGE_REL_PPC_SECREL HI 类型的重定位时这种重定位类型才是合法的。此重定位项的SymbolTableIndex域包含的是偏移而不是符号表的索引。
IMAGE_REL_PPC_SECRELLO
0x0013
重定位目标相对于它所在节开头的32位偏移的低16位。
IMAGE_REL_PPC_SECREL HI
0x001 4
重定位目标相对于它所在节开头的32位偏移的高16位。
IMAGE_REL_PPC_GPREL
0x0015
重定位目标相对于GP寄存器的16位偏移(带符号数)。
IMAGE_REL_PPC_TOKEN
0x0016
CLR 记号。
Intel 386处理器
为Intel 386及其兼容处理器定义了如下重定位类型指示符:
常量
描述
IMAGE_REL_I386_ABSOLUTE
0x0000
重定位被忽略。
IMAGE_REL_I386_DIR16
0x0001
不支持。
IMAGE_REL_I386_REL16
0x0002
不支持。
IMAGE_REL_I386_DIR32
0x0006
重定位目标的32位VA。
IMAGE_REL_I386_DIR32NB
0x0007
重定位目标的32位RVA。
IMAGE_REL_I386_SEG12
0x0009
不支持。
IMAGE_REL_I386_SECTION
0x000A
包含重定位目标的节的16位索引。用于支持调试信息。
IMAGE_REL_I386_SECREL
0x000B
重定位目标相对于它所在节开头的32位偏移。用于支持调试信息和 静态线程局部存储。
IMAGE_REL_I386_TOKEN
0x000C
CLR 记号。
IMAGE_REL_I386_SECREL7
0x000D
相对于重定位目标所在节基地址的7位偏移。
IMAGE_REL_I386_REL32
0x0014
重定位目标的32位相对偏移。用于支持x86的相对分支和CALL指令。
Intel Itanium处理器家族(IPF)
为Intel Itanium处理器家族及其兼容处理器定义了如下重定位类型指示符。注意指令重定位使用它所在的指令包的偏移以及相应的指令槽编号做为它的偏移:
常量
描述
IMAGE_REL_IA64_ABSOLUTE
0x0000
重定位被忽略。
IMAGE_REL_IA64_IMM14
0x0001
这种指令重定位后面能够跟着 IMAGE_REL_IA64_ADDEND 类型的重定位项,然后者的值在被插入到IMM14指令包的指定的指令槽中以前被加到目标地址上。这种重定位目标必须是绝对符号,不然这个映像必须被修正。
IMAGE_REL_IA64_IMM22
0x0002
这种指令重定位后面能够跟着 IMAGE_REL_IA64_ADDEND 类型的重定位项,然后者的值在被插入到IMM22指令包的指定的指令槽中以前被加到目标地址上。这种重定位目标必须是绝对符号,不然这个映像必须被修正。
IMAGE_REL_IA64_IMM64
0x0003
这种重定位项的指令槽编号必须为1。这种重定位后面能够跟着 IMAGE_REL_IA64_ADDEND 类型的重定位项,然后者的值在被 存储 到IMM64指令包的三个指令槽中以前被加到目标地址上。
IMAGE_REL_IA64_DIR32
0x0004
重定位目标的32位VA。仅支持使用 /LARGEADDRESSAWARE:NO 连接器选项生成的映像。
IMAGE_REL_IA64_DIR64
0x0005
重定位目标的64位VA。
IMAGE_REL_IA64_PCREL21B
0x0006
使用按16位边界对齐的重定位目标的25位相对偏移来修正指令。这个偏移的低4位全为0,所以并无被存储。
IMAGE_REL_IA64_PCREL21M
0x0007
使用按16位边界对齐的重定位目标的25位相对偏移来修正指令。这个偏移的低4位全为0,所以并无被存储。
IMAGE_REL_IA64_PCREL21F
0x0008
这种重定位目标偏移的LSB部分包含的是指令槽编号,其他部分包含的是指令包的地址。 使用按16位边界对齐的重定位目标的25位相对偏移来修正指令。这个偏移的低4位全为0,所以并无被存储。
IMAGE_REL_IA64_GPREL22
0x0009
这种指令重定位后面能够跟着 IMAGE_REL_IA64_ADDEND 类型的重定位项,后者的值被加到目标地址上,然后计算 GPREL22 指令包相对于GP的偏移并应用。
IMAGE_REL_IA64_LTOFF22
0x000A
使用重定位目标符号的常量表项相对于GP的22位偏移来修正指令。连接器根据这个重定位项以及可能跟着它的IMAGE_REL_IA64_ADDEND类型的重定位项来建立这个常量表项。
IMAGE_REL_IA64_SECTION
0x000B
包含重定位目标的节的16位索引。用于支持调试信息。
IMAGE_REL_IA64_SECREL22
0x000C
使用重定位目标相对于它所在节开头的22位偏移来修正指令。这种类型的重定位项后面能够紧跟着IMAGE_REL_IA64_ADDEND类型的重定位项,后者的Value域包含重定位目标相对于它所在节开头的32位偏移(无符号数)。
IMAGE_REL_IA64_SECREL64I
0x000D
这种重定位项的指令槽编号必须为1。 使用重定位目标相对于它所在节开头的64位偏移来修正指令。这种类型的重定位项后面能够紧跟着IMAGE_REL_IA64_ADDEND类型的重定位项,后者的Value域包含重定位目标相对于它所在节开头的32位偏移(无符号数)。
IMAGE_REL_IA64_SECREL32
0x000E
使用重定位目标相对于它所在节开头的32位偏移来修正的数据的地址。
IMAGE_REL_IA64_LTOFF 64
0x000 F
 
IMAGE_REL_IA64_DIR32NB
0x0010
目标的32位RVA。
IMAGE_REL_IA64_SREL14
0x0011
用于包含两个重定位目标之差的14位当即数(符号数)。对于连接器来讲这是一个说明域,代表编译器已经生成了这个值。
IMAGE_REL_IA64_SREL22
0x0012
用于包含两个重定位目标之差的22位当即数(符号数)。对于连接器来讲这是一个说明域,代表编译器已经生成了这个值。
IMAGE_REL_IA64_SREL32
0x0013
用于包含两个重定位目标之差的32位当即数(符号数)。对于连接器来讲这是一个说明域,代表编译器已经生成了这个值。
IMAGE_REL_IA64_UREL32
0x0014
用于包含两个重定位目标之差的32位当即数(无符号数)。对于连接器来讲这是一个说明域,代表编译器已经生成了这个值。
IMAGE_REL_IA64_PCREL60X
0x0015
相对于PC的60位修正,用于MLX指令包的BRL指令。
IMAGE_REL_IA64_PCREL60B
0x0016
相对于PC的60位修正。若是重定位目标偏移不超过一个25位域所能表示的范围(符号数),那么就在1号指令槽中使用NOP.B指令、2号指令槽中使用25位(最低4位全为0,舍弃)的BR指令将整个指令包转换成MBB指令包。
IMAGE_REL_IA64_PCREL60F
0x0017
相对于PC的60位修正。若是重定位目标偏移不超过一个25位域所能表示的范围(符号数),那么就在1号指令槽中使用NOP.F指令、2号指令槽中使用25位(最低4位全为0,舍弃)的BR指令将整个指令包转换成MFB指令包。
IMAGE_REL_IA64_PCREL60I
0x0018
相对于PC的60位修正。若是重定位目标偏移不超过一个25位域所能表示的范围(符号数),那么就在1号指令槽中使用NOP.I指令、2号指令槽中使用25位(最低4位全为0,舍弃)的BR指令将整个指令包转换成MIB指令包。
IMAGE_REL_IA64_PCREL60M
0x0019
相对于PC的60位修正。若是重定位目标偏移不超过一个25位域所能表示的范围(符号数),那么就在1号指令槽中使用NOP.M指令、2号指令槽中使用25位(最低4位全为0,舍弃)的BR指令将整个指令包转换成MMB指令包。
IMAGE_REL_IA64_IMMGPREL64
0x001 A
相对于GP的64位修正。
IMAGE_REL_IA64_TOKEN
0x001 B
CLR 记号。
IMAGE_REL_IA64_GPREL32
0x001 C
相对于GP的32位修正。
IMAGE_REL_IA64_ADDEND
0x001F
只有紧跟下列类型的重定位时这种重定位类型才是合法的: IMAGE_REL_IA64_ IMM14 IMAGE_REL_IA64_ IMM22 IMAGE_REL_IA64_ IMM64 IMAGE_REL_IA64_ GPREL22 IMAGE_REL_IA64_ LTOFF22 IMAGE_REL_IA64_ LTOFF64 IMAGE_REL_IA64_ SECREL22 IMAGE_REL_IA64_ SECREL64I IMAGE_REL_IA64_ SECREL32 。它的值是应用到指令包中的指令上的加数,而不是用于数据。
MIPS处理器
为MIPS处理器定义了如下重定位类型指示符:
常量
描述
IMAGE_REL_MIPS_ABSOLUTE
0x0000
重定位被忽略。
IMAGE_REL_MIPS_REFHALF
0x0001
重定位目标32位VA的高16位。
IMAGE_REL_MIPS_REFWORD
0x0002
重定位目标的32位VA。
IMAGE_REL_MIPS_JMPADDR
0x0003
重定位目标VA的低26位。用于支持MIPS平台的J和JAL指令。
IMAGE_REL_MIPS_REFHI
0x0004
重定位目标32位VA的高16位。它用于加载一个完整地址所需的两指令序列中的第一条指令。这种重定位类型后面必须紧跟IMAGE_REL_MIPS_PAIR类型的重定位项,然后者的SymbolTableIndex域包含的是一个16位偏移(符号数),这个偏移要被加到重定位目标位置的高16位。
IMAGE_REL_MIPS_REFLO
0x0005
重定位目标VA的低16位。
IMAGE_REL_MIPS_GPREL
0x0006
重定位目标相对于GP寄存器的16位偏移(符号数)。
IMAGE_REL_MIPS_LITERAL
0x0007
IMAGE_REL_MIPS_GPREL 相同。
IMAGE_REL_MIPS_SECTION
0x000A
包含重定位目标的节的16位索引。用于支持调试信息。
IMAGE_REL_MIPS_SECREL
0x000B
重定位目标相对于它所在节开头的32位偏移。用于支持调试信息和 静态线程局部存储。
IMAGE_REL_MIPS_SECRELLO
0x000C
重定位目标相对于它所在节开头的32位偏移的低16位。
IMAGE_REL_MIPS_SECRELHI
0x000D
重定位目标 相对于它所在节开头的 32 位VA的高16位。这种重定位类型后面必须紧跟 IMAGE_REL_MIPS_PAIR 类型的重定位项,然后者的SymbolTableIndex域包含的是一个16位偏移(符号数),这个偏移要被加到重定位符号位置的高16位。
IMAGE_REL_MIPS_JMPADDR16
0x0010
重定位目标VA的低26位。用于支持MIPS16的JAL指令。
IMAGE_REL_MIPS_REFWORDNB
0x0022
重定位目标的32位RVA。
IMAGE_REL_MIPS_PAIR
0x0025
只有紧跟 IMAGE_REL_MIPS_REFHI IMAGE_REL_MIPS_SECRELHI 类型的重定位时这种重定位类型才是合法的。此重定位项的SymbolTableIndex域包含的是偏移而不是符号表索引。
Mitsubishi M32R处理器
为Mitsubishi M32R处理器定义了如下重定位类型指示符:
常量
描述
IMAGE_REL_M32R_ABSOLUTE
0x0000
重定位被忽略。
IMAGE_REL_M32R_ADDR32
0x0001
重定位目标的32位VA。
IMAGE_REL_M32R_ADDR32NB
0x0002
重定位目标的32位RVA。
IMAGE_REL_M32R_ADDR24
0x0003
重定位目标的24位VA。
IMAGE_REL_M32R_GPREL16
0x0004
重定位目标相对于GP寄存器的16位偏移。
IMAGE_REL_M32R_PCREL24
0x0005
重定位目标相对于程序计数器(PC)的24位偏移,已经左移2位并按符号扩展。
IMAGE_REL_M32R_PCREL16
0x0006
重定位目标相对于PC的16位偏移,已经左移2位并按符号扩展。
IMAGE_REL_M32R_PCREL8
0x0007
重定位目标相对于PC的8位偏移,已经左移2位并按符号扩展。
IMAGE_REL_M32R_REFHALF
0x0008
重定位目标VA的16位MSB。
IMAGE_REL_M32R_REFHI
0x0009
重定位目标VA的16位MSB,已经按LSB符号扩展调整。它用于加载一个完整的32位地址所需的两指令序列中的第一条指令。这种重定位类型后面必须紧跟IMAGE_REL_M32R_PAIR类型的重定位项,然后者的SymbolTableIndex域包含的是一个16位偏移(符号数),这个偏移要被加到重定位符号位置的高16位。
IMAGE_REL_M32R_REFLO
0x000A
重定位目标VA的16位LSB。
IMAGE_REL_M32R_PAIR
0x000B
这种类型的重定位必须紧跟类型为 IMAGE_REL_M32R_REFHI 的重定位项。此重定位项的SymbolTableIndex域包含的是偏移而不是符号表索引。
IMAGE_REL_M32R_SECTION
0x000C
包含重定位目标的节的16位索引。用于支持调试信息。
IMAGE_REL_M32R_SECREL
0x000D
重定位目标相对于它所在节开头的32位偏移。用于支持调试信息和 静态线程局部存储。
IMAGE_REL_M32R_TOKEN
0x000E
CLR 记号。
5.3 COFF行号信息(不同意使用)
Microsoft 的工具已经再也不生成COFF行号信息,而且之后也不会再使用它了。
COFF 行号信息给出了源文件中代码与行号之间的关系。Microsoft的COFF行号信息格式与标准COFF行号信息格式相似,但已经被扩展,以便用单个节就能够与多个源文件中的行号关联。
COFF 行号信息由长度固定的记录组成的数组构成。数组的位置(文件偏移)与大小由节头给出。每一个行号记录格式以下:
偏移
大小
描述
0
4
Type (*)
这是由 SymbolTableIndex VirtualAddress 两个域组成的共用体。使用 SymbolTableIndex 仍是 RVA 依赖于 Linenumber 域的值。
4
2
Linenumber
若是此值非零,那么它表示行号(从1开始)。若是它为零,那么Type域表示一个函数在符号表中的索引。
 
Type 域是由 SymbolTableIndex VirtualAddress 两个4字节长的域组成的共用体:
偏移
大小
描述
0
4
SymbolTableIndex
当Linenumber 为零时使用此域,它表示一个函数在符号表中的索引。此格式用来指明一组行号记录与哪一个函数相关。
0
4
VirtualAddress
当Linenumber非零时使用此域,它表示与源代码中由Linenumber指定的那行代码对应的可执行代码的RVA。在目标文件中,它表示节中的VA。
 
一个行号记录,或者是将其Linenumber域设置为零, 同时(另外一个域) 指向符号表中的一个函数;或者是做为一个标准的行号记录:给出一个正整数(行号)以及在目标代码中相应的地址。
一组行号记录老是之前一种格式——符号表中函数的索引开头。若是这个行号记录是节中的第一个行号记录,而且节的COMDAT标志设置的话,那么它同时也是函数的COMDAT符号名。详细信息请参考5.5.6节“COMDAT节(仅适用于目标文件)”。此函数在符号表中的辅助记录有一个PointerToLinenumber域,它指向这个行号记录。
标识函数的记录后面跟着一些行号记录,它们给出了实际的行号信息(也就是说,这些记录的Linenumber域都大于0)。这些项(中的Linenumber域)从1开始(相对于函数的开头),每个表示函数源代码中的一行(除了第一行)。
例如在下面的例子中,第一个行号记录会列出 ReverseSign 函数( ReverseSign 函数的 SymbolTableIndex 和被设置为0的 Linenumber 域)。它后面的记录的Linenumber域的 值依次为一、2和3,它们分别对应着源代码中相应的行,以下所示:
// ReverseSign 函数前面的代码
    int ReverseSign(int i)
1: {
2:      return -1 * i;
3: }
 
5.4 COFF符号表
本节中提到的符号表继承自传统的COFF格式。它与 Microsoft Visual C++® 调试信息大相径庭。一个文件能够同时包含COFF符号表和Visual C++调试信息,两者是分开的。一些Microsoft的工具出于有限但重要的目的使用符号表,例如用于向连接器传递COMDAT信息。符号表中列出了节名、文件名以及代码与数据符号。
符号表的位置由COFF文件头给出。
符号表是一个由记录组成的数组,每一个记录长18字节。它们或者是标准符号表记录,或者是辅助符号表记录。标准符号表记录定义了一个符号或名称,格式以下
偏移
大小
描述
0
8
Name (*)
符号名称,这是一个由三个成员组成的共用体。若是名称的长度不超过8个字节,那么它就是一个8字节长的数组。要获取更多信息,请参考5.4.1节“符号名称表示”。
8
4
Value
与符号相关的值。其意义依赖于 SectionNumber StorageClass 两个域。它一般表示可重定位的地址。
12
2
SectionNumber
这个带符号整数是节表的索引(从1开始),用以标识定义此符号的节。一些值有特殊的含义,详细信息请参考5.4.2节“ SectionNumber 域的 值”。
14
2
Type
一个表示类型的数字。Microsoft的工具将它设置为0x20(若是是函数)或者0x0(若是不是函数)。要获取更多信息,请参考5.4.3节“类型表示”。
16
1
StorageClass
这是一个表示存储类别的枚举类型值。要获取更多信息,请参考5.4.4节“存储类别”。
17
1
NumberOfAuxSymbols
跟在本记录后面的辅助符号表项的个数。
每一个标准符号表记录后面紧跟着零个或多个辅助符号表记录,但一般状况下并不会超过一个(除了带长文件名的.file记录)。每一个辅助符号表记录的大小与标准符号表记录相同(都是18字节),但它并非又定义了一个新的符号,而是给出了与上一个定义的符号相关的附加信息。辅助符号表记录有好几种格式,使用哪种取决于StorageClass域的值。当前已经为辅助符号表记录定义的格式将在5.5节“辅助符号表记录”中列出。
处理COFF符号表的工具必须忽略意义不明的辅助符号表记录。这样容许往后对符号表的格式进行扩展以便添加新的辅助符号表记录而不会使现存的工具失效。
5.4.1符号名称表示
若是符号名称长度不超过8个字节,那么符号表的ShortName域就是包含符号名自己的一个8字节长的数组;不然的话,它给出了字符串表中的一个偏移地址。要肯定它究竟是名称自己仍是偏移地址,测试一下它的前4个字节是否等于0。
一般名称都被认为是以NULL结尾的UTF-8格式的字符串。

偏移
大小
描述
0
8
ShortName
8 字节长的数组。若是名称长度小于8字节,在它的右边用NULL填充。
0
4
Zeroes
若是名称长度大于8字节,那么这个域被设置为全0。
4
4
Offset
字符串表中的一个偏移地址。
5.4.2 SectionNumber域的
一般符号表项中的SectionNumber域是节表的索引(从1开始)。可是这个域是带符号整数,所以它能够为负值。下面这些小于1的值有特殊含义:
常量
描述
IMAGE_SYM_UNDEFINED
0
还没有为此符号记录分配一个节。这个零值代表引用了一个定义在其它地方的外部符号;而非零值则代表是一个普通符号,其大小由Value域给出。
IMAGE_SYM_ABSOLUTE
-1
此符号是个绝对符号(不可重定位),而且不是地址。
IMAGE_SYM_DEBUG
-2
此符号提供普通类型信息或者调试信息,但它并不对应于某一个节。Microsoft的工具将.file记录(存储类别为FILE)设置为这个值。
5.4.3类型表示
符号表项的Type域占2个字节,其中的每个字节都表示类型信息。低位字节(LSB)表示简单(基本)数据类型,高位字节(MSB)表示复杂类型(若是存在):
MSB
LSB
复杂类型:无、指针、函数、数组。
基本类型:整数、浮点数等。
 
尽管Microsoft的工具一般不使用这个域并将LSB设置为0,但仍是为基本类型定义了如下这些值。Microsoft的工具使用Visual C++调试信息来指明类型。可是出于完整性考虑,将可能出现的值列于下表:
常量
描述
IMAGE_SYM_TYPE_NULL
0
类型信息不存在,或者是未知的基本类型。Microsoft的工具使用这个值。
IMAGE_SYM_TYPE_VOID
1
不是合法类型;用于void指针和函数。
IMAGE_SYM_TYPE_CHAR
2
字符(带符号的1个字节)。
IMAGE_SYM_TYPE_SHORT
3
长度为2个字节的带符号整数。
IMAGE_SYM_TYPE_INT
4
天然的整数类型(在Windows中一般为4个字节)。
IMAGE_SYM_TYPE_LONG
5
长度为4个字节的带符号整数。
IMAGE_SYM_TYPE_FLOAT
6
长度为4个字节的浮点数。
IMAGE_SYM_TYPE_DOUBLE
7
长度为8个字节的浮点数。
IMAGE_SYM_TYPE_STRUCT
8
结构体。
IMAGE_SYM_TYPE_UNION
9
共用体。
IMAGE_SYM_TYPE_ENUM
10
枚举类型。
IMAGE_SYM_TYPE_MOE
11
枚举类型成员(具体值)。
IMAGE_SYM_TYPE_BYTE
12
字节;长度为1个字节的无符号整数。
IMAGE_SYM_TYPE_WORD
13
字;长度两个字节的无符号整数。
IMAGE_SYM_TYPE_UINT
14
长度为天然尺寸的无符号整数(一般为4个字节)。
IMAGE_SYM_TYPE_DWORD
15
长度为4个字节的无符号整数。
 
高位字节指出符号是指向由LSB指定的基本类型的指针、返回由LSB指定的基本类型的函数仍是由LSB指定的基本类型组成的数组。Microsoft的工具仅使用这个域来指出这个符号是否是函数,所以最后的Type域只有0x0和0x20这两个值。可是其它工具可使用这个域来传递更多信息。
正确地指定函数属性很是重要。增量连接须要这个信息才能正确地工做。对于某些平台而言,可能会出于其它目的而使用这个信息。
常量
描述
IMAGE_SYM_DTYPE_NULL
0
非导出类型;此符号是简单的标量变量。
IMAGE_SYM_DTYPE_POINTER
1
此符号是指向基本类型的指针。
IMAGE_SYM_DTYPE_FUNCTION
2
此符号是返回基本类型的函数。
IMAGE_SYM_DTYPE_ARRAY
3
此符号是由基本类型组成的数组。
5.4.4存储类别
符号表中的StorageClass域指出符号具体的存储类别。下表列出了全部可能的取值。注意StorageClass域是长度为1个字节的无符号整数。所以若是这个域的值为-1的话,实际上应该被看做是与它相等的无符号数,也就是0xFF。
尽管传统的COFF格式使用许多存储类别,可是Microsoft的工具使用Visual C++调试信息来表示大部分符号信息,它一般仅使用四种存储类别: EXTERNAL (2)、 STATIC (3)、 FUNCTION (101)和FILE(103)。下表中出现的“Value”都表示符号表记录中的Value域(它的意义依赖于存储类别的值)。
常量
描述以及对Value域的解释
IMAGE_SYM_CLASS_END_OF_FUNCTION
-1
(0xFF)
表示函数结尾的特殊符号,用于调试。
IMAGE_SYM_CLASS_NULL
0
未被赋予存储类别。
IMAGE_SYM_CLASS_AUTOMATIC
1
自动(堆栈)变量。Value域指出此变量在栈帧中的偏移。
IMAGE_SYM_CLASS_EXTERNAL
2
Microsoft 的工具使用此值来表示外部符号。若是SectionNumber域为0(IMAGE_SYM_UNDEFINED),那么Value域给出大小;若是SectionNumber 域不为0,那么Value域给出节中的偏移。
IMAGE_SYM_CLASS_STATIC
3
符号在节中的偏移。若是Value域为0,那么此符号表示节名。
IMAGE_SYM_CLASS_REGISTER
4
寄存器变量。Value域给出寄存器编号。
IMAGE_SYM_CLASS_EXTERNAL_DEF
5
在外部定义的符号。
IMAGE_SYM_CLASS_LABEL
6
模块中定义的代码标号。Value域给出此符号在节中的偏移。
IMAGE_SYM_CLASS_UNDEFINED_LABEL
7
引用的未定义的代码标号。
IMAGE_SYM_CLASS_MEMBER_OF_STRUCT
8
结构体成员。Value域指出是第几个成员。
IMAGE_SYM_CLASS_ARGUMENT
9
函数的形式参数(形参)。Value域指出是第几个参数。
IMAGE_SYM_CLASS_STRUCT_TAG
10
结构体名。
IMAGE_SYM_CLASS_MEMBER_OF_UNION
11
共用体成员。Value域指出是第几个成员。
IMAGE_SYM_CLASS_UNION_TAG
12
共用体名。
IMAGE_SYM_CLASS_TYPE_DEFINITION
13
Typedef
IMAGE_SYM_CLASS_UNDEFINED_STATIC
14
静态数据声明。
IMAGE_SYM_CLASS_ENUM_TAG
15
枚举类型名。
IMAGE_SYM_CLASS_MEMBER_OF_ENUM
16
枚举类型成员。Value域指出是第几个成员。
IMAGE_SYM_CLASS_REGISTER_PARAM
17
寄存器参数。
IMAGE_SYM_CLASS_BIT_FIELD
18
位域。Value域指出是位域中的第几个位。
IMAGE_SYM_CLASS_BLOCK
100
 .bb beginning of block ,块开头 ) .eb记录 end of block ,块结尾)。Value域是代码位置,它是一个可重定位的地址。
IMAGE_SYM_CLASS_FUNCTION
101
Microsoft 的工具用此值来表示定义函数范围的符号记录,这些符号记录分别是: .bf (begin fu nction ,函数开头)、 .ef end function ,函数结尾)以及 .lf lines in function ,函数中的行)。对于.lf 记录来讲,Value域给出了源代码中此函数所占的行数。对于.ef记录来讲,Value域给出了函数代码的大小。
IMAGE_SYM_CLASS_END_OF_STRUCT
102
结构体末尾。
IMAGE_SYM_CLASS_FILE
103
Microsoft 的工具以及传统COFF格式都使用此值来表示源文件符号记录。这种符号表记录后面跟着给出文件名的辅助符号表记录。
IMAGE_SYM_CLASS_SECTION
104
节的定义(Microsoft的工具使用STATIC存储类别代替)。
IMAGE_SYM_CLASS_WEAK_EXTERNAL
105
弱外部符号。要获取更多信息,请参考5.5.3节“辅助符号表记录格式之三:弱外部符号”。
IMAGE_SYM_CLASS_CLR_TOKEN
107
表示CLR记号的符号。它的名称是这个记号的十六进制值的ASCII码表示。要获取更多信息,请参考5.5.7节“CLR记号定义”。
5.5辅助符号表记录
辅助符号表记录老是跟在一些标准符号表记录以后并应用于这些符号表记录。它的格式并不固定,只要处理它的工具可以识别就能够了,但必须保证其长度是18个字节,以便整个符号表能够被看成一个数组来处理。当前Microsoft的工具能够识别如下类型的辅助符号表记录:函数定义、函数开头和结尾符号(.bf.ef)、弱外部符号、文件名以及节的定义。
传统的COFF格式中还包括用于数组和结构体的辅助符号表记录。可是Microsft的工具并不使用它们,而是将符号信息按照Visual C++调试信息格式存储在调试节中。
5.5.1辅助符号表记录格式之一:函数定义
若是一个符号表记录拥有下列属性:存储类别为EXTERNAL(2)、Type域的值代表它是一个函数(0x20)以及SectionNumber域的值大于0,它就标志着函数的开头。注意若是一个符号表记录SectionNumber域的值为IMAGE_SYM_UNDEFINED(0),那么它并不定义一个函数,也没有相应的辅助符号表 记录。可以定义函数的符号表记录后面跟着以下格式的辅助符号表记录:

偏移
大小
描述
0
4
TagIndex
相应的.bf(函数开头)记录在符号表中的索引。
4
4
TotalSize
函数经编译后生成的可执行代码的大小。若是此函数单独成节,那么根据对齐值的不一样,节头中的SizeOfRawData域可能大于或等于这个域。
8
4
PointerToLinenumber
若是此函数存在行号记录,那么这个值表示它的第一个COFF行号记录的文件偏移;若是不存在,那么这个值为0。要获取更多信息,请参考5.3节“COFF行号信息(不同意使用)”。
12
4
PointerToNextFunction
对应于下一个函数的符号表记录在符号表中的索引。若是此函数是符号表中的最后一个函数,那么这个域的值为0。
16
2
未用
5.5.2辅助符号表记录格式之二:.bf和.ef符号
对于符号表中的每一个函数定义,有三个相应的符号表记录分别用来描述函数开头、函数结尾以及此函数在源文件中所占的行数。这三个符号表记录的存储类别都是FUNCTION(101):
·         一个名为.bf的符号表记录。此记录的Value域未用。
·         一个名为.lf的符号表记录。此记录的Value域给出了这个函数所占的行数。
·         一个名为.ef的符号表记录。此记录的Value域的值与定义函数的符号表记录的TotalSize域的值相同。
 
.bf .ef符号表记录(不包括.lf记录)后面跟着以下格式的辅助符号表记录:
偏移
大小
描述
0
4
未用
4
2
Linenumber
源文件中实际的行号,按顺序排列(一、二、3等等)。.bf.ef记录都使用这个域。
6
6
未用
12
4
PointerToNextFunction (仅用于 .bf 符号表记录)
下一个.bf符号表记录在符号表中的索引。若是此函数是符号表中的最后一个函数,那么这个域的值为0。.ef记录并不使用这个域。
16
2
未用
5.5.3辅助符号表记录格式之三:弱外部符号
“弱外部符号”是为了在连接时能得到更大的灵活性而应用于目标文件的一种机制。模块中能够包含一个没法解析的外部符号(假设为sym1),但它也能够同时包含一个相应的辅助符号表记录来指明当连接时找不到sym1时能够用另一个外部符号(假设为sym2)来代替。
若是连接时能找到sym1的定义,那么外部对它的引用能够正常解析。不然全部对sym1这个弱外部符号的引用都用sym2来代替。而sym2这个外部符号在连接时必须可以找到;一般它就被定义在对sym1进行弱外部引用的模块中。
表示弱外部符号的符号表记录,其存储类别是 EXTERNAL SectionNumber 域的值为 IMAGE_SYM_UNDEFINED (0),Value域的值为0。弱外部符号记录后面跟着以下格式的辅助符号表记录:
偏移
大小
描述
0
4
TagIndex
sym2 在符号表中的索引。若是连接时找不到sym1就用它代替。
4
4
Characteristics
若是这个值为 IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY ,代表连接时不在库中查找sym1。
若是这个值为 IMAGE_WEAK_EXTERN_SEARCH_LIBRARY ,代表连接时在库中查找sym1。
若是这个值为 IMAGE_WEAK_EXTERN_SEARCH_ALIAS ,代表sym1是sym2的别名。
8
10
未用
 
注意在 WINNT.H 文件中并无定义这个 Characteristics 域,而是用 TotalSize 域来代替。
5.5.4辅助符号表记录格式之四:文件
此格式的辅助符号表记录跟在存储类别为FILE(103)的符号表记录以后。这个符号表记录的符号名自己应该是.file,而跟着它的辅助记录给出了源文件名。
偏移
大小
描述
0
18
File Name
表示源文件名的ANSI字符串。若是源文件名的长度小于最大长度,用NULL填充。
5.5.5辅助符号表记录格式之五:节定义
此格式的辅助符号表记录跟在定义节的符号表记录以后。对于定义节的符号表记录来讲,其符号名就是相应的节名(例如.text.drectve)且存储类别为STATIC(3)。而相应的辅助记录提供了关于这个节的信息。所以这样的辅助符号表记录中的一些信息与节头中的信息是重复的。
偏移
大小
描述
0
4
Length
节中数据的大小。与节头的 SizeOfRawData 域同样。
4
2
NumberOfRelocations
此节中重定位项的数目。
6
2
NumberOfLinenumbers
此节中行号信息项的数目。
8
4
CheckSum
公共数据的校验和。只有节头中设置了IMAGE_SCN_LNK_COMDAT标志时才使用此域。要获取更多信息,请参考5.5.6节“COMDAT节(仅适用于目标文件)”。
12
2
Number
与此节相关的节在节表中的索引(从1开始)。当COMDAT的Selection域 为5时才使用这个域。
14
1
Selection
表示COMDAT选择方式的数字。 这个域只用于 COMDAT 节。
15
3
未用
5.5.6 COMDAT节(仅适用于目标文件)
若是一个节为COMDAT节,那么定义这个节的符号表记录后跟着的辅助记录中的Selection域是可用的。COMDAT节是一种能够由多个目标文件定义的节。(节头中的Characteristics域设置了IMAGE_SCN_LNK_COMDAT标志)。Selection域的值决定了连接器在解析多个COMDAT节定义时所采用的方式。
第一个其SectionNumber域指向COMDAT节的符号必须是定义节的符号。 这个符号的名称就是节名,其Value域的值为0,SectionNumber域指向咱们正在讨论的COMDAT节,Type域的值为 IMAGE_SYM_TYPE_NULL ,StorageClass域的值为IMAGE_SYM_CLASS_STATIC,而且有一个辅助记录。第二个符号被称为“COMDAT符号”,连接器将它与Selection域配合起来使用。
Selection 域的值以下所示:
  常量
描述
IMAGE_COMDAT_SELECT_NODUPLICATES
1
若是此符号已经被定义过,连接器将生成一个“ multiply defined symbol (符号多重定义)”错误。
IMAGE_COMDAT_SELECT_ANY
2
连接器从这些定义同一个COMDAT符号的节中任选一个,其他(未被选中)的节都被移除。
IMAGE_COMDAT_SELECT_SAME_SIZE
3
连接器从定义这个符号的多个节中任选一个。若是全部这些定义大小不等,连接器将生成一个“符号多重定义”错误。
IMAGE_COMDAT_SELECT_EXACT_MATCH
4
连接器从定义这个符号的多个节中任选一个。若是全部这些定义不严格一致,连接器将生成一个“符号多重定义”错误。
IMAGE_COMDAT_SELECT_ASSOCIATIVE
5
若是“其它某个”COMDAT节被连接的话,此节也要被连接。这里的“其它某个”节由与定义此节的符号表记录相关的辅助符号表记录的Number域给出。这个设置对于那些在多个节中都有其相关部分(例如代码在一个节中而数据在另外一个节中)但必须做为一个总体进行连接或丢弃的定义很是有用。与此节关联的这个“其它某个”节必须也是COMDAT节而且它不能再与其它COMDAT节关联(也就是说,这个“其它某个”节不能将Selection域设置为IMAGE_COMDAT_SELECT_ASSOCIATIVE)。
IMAGE_COMDAT_SELECT_LARGEST
6
连接器从这个符号的全部定义中选取长度最大的进行连接。若是长度最大的不止一个,那么就在这几个最大的中任选一个。
5.5.7 CLR记号定义(仅适用于目标文件)
这种辅助符号表记录一般跟在存储类别为IMAGE_SYM_CLASS_CLR_TOKEN的符号表记录以后。它用来联系CLR记号与COFF符号表的名称空间。
偏移
大小
描述
0
1
bAuxType
必须为 IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF (1)。
1
1
bReserved
保留,必须为0。
2
4
SymbolTableIndex
此CLR记号定义涉及的COFF符号在符号表中的索引。
6
12
保留,必须为0。
5.6 COFF字符串表
COFF 符号表后紧跟着的是COFF字符串表。它的位置能够经过将COFF文件头中符号表的地址加上符号总数乘以每一个符号的大小获得。
COFF 字符串表开头的4个字节存储的是字符串表的总大小(以字节计)。这个大小包括这个域自己。所以若是字符串表中不包含任何字符串时,这个值应该为4。
大小后面是一些以NULL结尾的字符串,COFF符号表中的符号指向这些字符串。
5.7属性证书表(仅适用于映像文件)
能够给映像文件添加属性证书表使它与属性证书相关联。属性证书表由一组连续的按八进制字(从任意字节边界开始的16个连续字节)边界对齐的属性证书表项组成。每一个属性证书表项格式以下:
偏移
大小
描述
0
4
dwLength
指出 bCertificate 域的长度。
4
2
wRevision
证书版本号。要获取详细信息,请参考本表后面的内容。
6
2
wCertificateType
指出 bCertificate 内容的类型。要获取详细信息,请参考本表后面的内容。
8
参考后面的内容
bCertificate
这个域包含一个证书,例如Authenticode签名。要获取详细信息,请参考本表后面的内容。
 
可选文件头中的数据目录中的Certificate Table(证书表)项中的VirtualAddress域给出了属性证书表中第一个属性证书表项的文件偏移。对于后续的属性证书表项,能够经过将当前属性证书表项的文件偏移加上其dwLength域的值并将结果向上舍入为8字节的倍数来访问。后续的属性证书表项能够一直以这种方式访问直到这些dwLength域(已经向上舍入为8字节的倍数)的和等于可选文件头中的数据目录中的Certificate Table项中的Size域的值。若是这些dwLength域(已经向上舍入为8字节的倍数)的和最后不等于Size域的值,那要么属性证书表被破坏了,要么Size域被破坏了。
例如若是 可选文件头中的数据目录中的Certificate Table项内容以下:
virtual address = 0x5000
size = 0x1000
 
那么第一个证书从文件偏移0x5000处开始。要访问后续的属性证书表项,按如下步骤进行:
1. 将第一个属性证书的dwLength域的值加到前面提到的开始地址(0x5000)处。
2. 将第一步获得的结果向上舍入到与它最接近的8字节的倍数,这个倍数就是第二个属性证书项的文件偏移。
3. 将第二步获得的文件偏移加上第二个属性证书项的dwLength域的值并将结果向上舍入到与它最接近的8字节的倍数,这个倍数就是第三个属性证书项的文件偏移。
4. 重复第三步的操做以访问后续的属性证书项,直到计算出的偏移等于0x6000 (开始地址0x5000 + 总大小 0x1000 ),它表示你已经遍历了整个属性证书表。
 
你也能够在一个循环中调用 Win32® 函数 ImageEnumerateCertificates 来枚举属性证书表项。本规范最后的“参考信息”中给出了此函数信息的连接。
属性证书表项能够包含任何类型的证书,只要它有正确的 dwLength 值、唯一的 wRevision 值和唯一的 wCertificateType 值。最经常使用的类型是 WIN_CERTIFICATE 结构,Wintrust.h文件给出了它的内容,本节后面将要讨论它。
WIN_CERTIFICATE 结构的wRevision域能够选用(但不限于)如下值:
名称
注意
0x0100
WI N_CERT_REVISION_1_0
版本1, WIN_CERTIFICATE 结构的遗留版本。支持它只是为了校验之前的Authenticode签名。
0x0200
WIN_CERT_REVISION_2_0
版本2是 WIN_CERTIFICATE 结构的当前版本。
 
WIN_CERT IFICATE 结构的 wCertificateType 域能够选用(但不限于)的值列于下表。注意其中一些值当前并不支持。
名称
注意
0x0001
WIN_CERT_TYPE_X509 
bCertificate 包含的是 X.509 证书。不支持。
0x0002
WIN_CERT_TYPE_PKCS_SIGNED_DATA
bCertificate 包含的是 PKCS#7 SignedData 结构。
0x0003
WIN_CERT_TYPE_RESERVED_1
保留。
0x0004
WIN_CERT_TYPE_TS_STACK_SIGNED
终端服务器协议栈证书签名。不支持。
 
WIN_CERTIFICATE 结构的 bCertificate 域是一个长度可变的字节数组,其中内容的类型由 wCertificateType 域指定。Authenticode支持的类型是WIN_CERT_TYPE_PKCS_SIGNED_DATA,它是一个PKCS#7 SignedData结构。要获取更多信息,请参考“Windows Authenticode可移植可执行签名格式”。
若是bCertificate的内容并不在八进制字边界结束,那么从bCertificate的内容最后到八进制字边界之间用0填充。
·         dwLength 域的值指出了 bCertificate 的大小,它并不包括填充的内容。
·         可选文件头中的数据目录(3.4.3节)中的 Certificates Table 项的Size域指出了属性证书表的大小,它包括填充的内容。
 
要获取关于如何使用ImageHlp API来枚举、添加和删除PE文件中的证书方面的详细信息,请参考“ImageHlp函数”。
5.7.1证书数据
如上节所述,属性证书表中能够包含任何类型的证书。用于确保PE文件完整性的证书能够包含PE映像散列。
PE 映像散列(或者称为文件散列)与文件校验和相似,它们的散列算法都生成一个与文件完整性有关消息摘要。可是校验和是用简单的算法生成的,它主要用来检测保存在磁盘上的一块内存是否已经被破坏以及存储在那里的值 是否已经被改变。文件散列与校验和的相同之处在于它也检测文件是否被破坏。但与大多数校验和算法不一样的是,要对一个文件进行修改并同时保持它的文件散列与原始(未修改的)形式一致是极其困难的。所以文件散列能够用来检测诸如一些病毒、黑客或者木马程序对文件进行的有意的、甚至是很是细微的修改。
当将映像中的内容包含进证书时,映像摘要必须排除PE映像中的某些域,例如Checksum域以及可选文件头中的数据目录中的Certificate Table 项。这是由于给PE文件添加一个证书会改变这些域的值,而且文件的散列值也不相同。
Win32 函数ImageGetDigestStream 为散列函数 提供了一个目标PE文件的数据流。当为PE文件添加或删除证书时这个数据流保持不变。根据传递给ImageGetDigestStream函数的参数的不一样,PE映像中的一些数据可能会在散列计算时被忽略。本规范最后的“参考信息”中给出了此函数信息的连接。
5.8延迟加载导入表(仅适用于映像文件)
将这些表添加到映像文件中是为了给“应用程序直到首次调用某个DLL中的函数或数据时才加载这个DLL(即延迟加载)”这种行为提供一种通一的机制。这些表的格式与将要在6.4节“.idata节”中描述的传统导入表的格式一致。这里仅讨论少量细节。
5.8.1延迟加载目录表
延迟加载目录表是导入目录表的副本,能够从可选文件头中的数据目录中的Delay Import Descriptor(延迟导入描述符)域(偏移200处)获取它。其格式以下:
偏移
大小
描述
0
4
Attributes
必须为0。
4
4
Name
被加载DLL名称的RVA。这个名称位于映像文件的只读数据节中。
8
4
Module Handle
被延迟加载DLL模块句柄(在映像的数据节中)的RVA。它供管理延迟加载的例程存储之用。
12
4
Delay Import Address Table
延迟加载导入地址表的RVA。要获取更多信息,请参考5.8.5节“延迟导入地址表(IAT)”。
16
4
Delay Import Name Table
延迟加载名称表的RVA。这个表包含了须要被加载的导入符号的名称。它与导入名称表的格式一致。要获取更多信息,请参考6.4.3节“提示/名称表”。
20
4
Bound Delay Import Table
绑定延迟加载地址表(若是存在)的RVA。
24
4
Unload Delay Import Table
卸载延迟加载地址表(若是存在)的RVA。这个表是延迟导入地址表的精确副本。若是调用者卸载了这个DLL,应该将这个表复制回去以覆盖延迟导入地址表,以便后续对这个DLL的调用能够继续正确地使用形实转换机制。
28
4
Time Stamp
此映像绑定到的DLL的时间戳。
 
对于这个结构中使用到的表来讲,它们的组织形式与存储格式与传统的导入表同样,就像是它们的副本。要获取更多信息,请参考4.6节“.idata节”。
5.8.2属性
至今还没有定义属性标志。连接器在生成映像文件时将此域设置为 0 。咱们能够在未来扩展这个结构时用它来指明添加了新域,或者用它来指明延迟加载或卸载辅助函数的行为。
5.8.3名称
须要被延迟加载的DLL的名称被存储在映像文件的只读数据节中。能够经过 szName 域引用它。
5.8.4模块句柄
要被延迟加载的DLL的句柄被存储在映像文件的数据节中。 phmod 域指向这个 句柄。延迟加载辅助函数使用这个位置存储要被延迟加载的DLL的模块句柄。
5.8.5延迟导入地址表
能够经过延迟导入描述符的 pIAT 域引用延迟导入地址表(IAT)。延迟加载辅助函数用导入符号的实际地址来更新这些指针,以便起转换做用的这部分代码不会陷入 循环调用之中。能够经过表达式 pINT->u1.Function 来访问 这些函数指针
5.8.6延迟导入名称表
延迟导入名称表(INT)包含了可能须要被加载的导入符号的名称。它们的排列方式与IAT中的函数指针同样。它们的结构与标准的INT同样,能够经过表达式 pINT->u1.AddressOfData->Name[0] 进行访问
5.8.7延迟绑定导入地址表和时间戳
延迟绑定导入地址表(BIAT)是由IMAGE_THUNK_DATA结构组成的数组,它是可选的。它与延迟加载目录表中的Time Stamp域一块儿被用于后处理绑定阶段。
5.8.8延迟卸载导入地址表
延迟卸载导入地址表(UIAT)是由IMAGE_THUNK_DATA结构组成的数组,它是可选的。卸载代码用它来处理明确的卸载请求。它由只读节中已初始化的数据组成,这些数据是原始IAT的精确副本。在处理卸载请求时,能够释放这个DLL,同时将 *phmod 清零,并用UIAT覆盖IAT, 以便将一切都还原到预加载时的状态。
6特殊的节
典型的COFF节包含的是普通代码或数据,连接器与Microsoft Win32®加载器并不须要知道其中的内容就能够处理它们。这些内容只与将要连接的或执行的应用程序有关。
可是目标文件与映像文件中的某些COFF节却有特殊含义。因为在节头中为这些节设置了特殊的标志,或者可选文件头中的某些域指向这些节,或者节名自己指出了节的特殊做用,因此工具和加载器能够识别它们。(尽管节名自己并不代表节的特殊做用,但节名都是约定俗成的,所以本规范的做者在任何状况下均可以使用节名。)
下表描述了保留的节以及它们的属性,后面是对出如今可执行文件中的节以及包含元数据用于扩展目的的节的详细描述。
节名
内容
特征
.bss
未初始化的数据(自由格式)
IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |                 IMAGE_SCN_MEM_WRITE
.cormeta
CLR 元数据,它代表目标文件中包含托管代码
IMAGE_SCN_LNK_INFO
.data
已初始化的数据(自由格式)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |          IMAGE_SCN_MEM_WRITE
.debug$F
生成的FPO调试信息(仅适用于目标文件,仅用于x86平台,现已被舍弃)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |          IMAGE_SCN_MEM_DISCARDABLE
.debug$P
预编译的调试类型信息(仅适用于目标文件)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |          IMAGE_SCN_MEM_DISCARDABLE
.debug$S
调试符号信息(仅适 用于目标文件)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |          IMAGE_SCN_MEM_DISCARDABLE
.debug$T
调试类型信息(仅适用于目标文件)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |          IMAGE_SCN_MEM_DISCARDABLE
.drectve
连接器选项
IMAGE_SCN_LNK_INFO
.edata
导出表
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
.idata
导入表
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE
.idlsym
包含已注册的SEH(仅适用于映像文件),它们用以支持IDL属性。要获取更多信息,请参考本规范最后“参考信息”中的“IDL属性”。
IMAGE_SCN_LNK_INFO
.pdata
异常信息
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
.rdata
只读的已初始化数据
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
.reloc
映像文件的重定位信息
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |                IMAGE_SCN_MEM_DISCARDABLE
.rsrc
资源目录
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
.sbss
GP相关的未初始化数据(自由格式)
IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |                 IMAGE_SCN_MEM_WRITE |                IMAGE _SCN_GPREL
其中 IMAGE_SCN_GPREL 标志仅用于IA64平台,不能用于其它平台。此标志只能用于目标文件。当映像文件中出现这种类型的节时,必定不能设置这个标志。
.sdata
GP相关的已初始化数据(自由格式)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |                IMAGE_SCN_MEM_WRITE |                IMAGE _SCN_GPREL
其中 IMAGE_SCN_GPREL 标志仅用于IA64平台,不能用于其它平台。此标志只能用于目标文件。当映像文件中出现这种类型的节时,必定不能设置这个标志。
.srdata
GP相关的只读数据(自由格式)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |                IMAGE _SCN_GPREL
其中 IMAGE_SCN_GPREL 标志仅用于IA64平台,不能用于其它平台。此标志只能用于目标文件。当映像文件中出现这种类型的节时,必定不能设置这个标志。
.sxdata
已注册的异常处理程序数据(自由格式,仅适用于目标文件,仅用于x86平台)
IMAGE_SCN_LNK_INFO
这个节中包含目标文件中的代码所涉及到的全部异常处理程序在符号表中的索引。这些符号能够是IMAGE_SYM_UNDEFINED类型的符号,也能够是定义在那个模块中的符号。
.text
可执行代码(自由格式)
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE |                 IIMAGE_SCN_MEM_READ
.tls
线程局部存储(仅适用于目标文件)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |                IMAGE_SCN_MEM_WRITE
.tls$
线程局部存储(仅适用于目标文件)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |                IMAGE_SCN_MEM_WRITE
.vsdata
GP相关的已初始化数据(自由格式,仅适用于ARM、SH4和Thumb平台)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |                IMAGE_SCN_MEM_WRITE
.xdata
异常信息(自由格式)
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
 
上表中列出的一些节被标记为“仅适用于目标文件”或 “仅适用于映像文件”,它们表示这些节的特殊含义只是分别对于目标文件或者映像文件来讲的。标记为“仅适用于映像文件”的节仍然能够首先出如今目标文件中,最后再成为映像文件的一部分,但这个节对于连接器来讲并无特殊含义,它仅对于映像文件加载器才有特殊含义。
6.1 .debug
在目标文件中,.debug 节包含编译器生成的调试信息;在映像文件中,它包含生成的所有调试信息。本节描述了目标文件和映像文件中调试信息的封装。
下一节描述调试目录的格式,它能够被放在映像文件中的任何地方。后面几节描述目标文件中包含调试信息的成组的节。
默认状况下调试信息并不映射到映像的地址空间中。只有当调试信息被映射到地址空间中时.debug节才会存在。
6.1.1调试目录(仅适用于映像文件)
映像文件中包含一个可选的调试目录,它给出了调试信息的格式及位置。这个目录是一个由调试目录项组成的数组,它的位置和大小由可选文件头给出。
调试目录能够位于一个可丢弃的.debug 节(若是存在)中,或者位于映像文件的其它节中,或者不在任何节中。
每一个调试目录项给出了一块调试信息的位置和大小。若是调试信息没有被节头包含(也就是说,它位于映像文件中但并无被映射到运行时地址空间中)的话,那么这个指定的RVA能够为0。若是被映射的话,这个RVA就是它的实际地址。
调试目录项格式以下:
偏移
大小
描述
0
4
Characteristics
保留,必须为0。
4
4
TimeDateStamp
调试数据被建立的日期和时间。
8
2
MajorVersion
调试数据格式的主版本号。
10
2
MinorVersion
调试数据格式的次版本号。
12
4
Type
调试信息的格式。这个域的存在使得能够支持多个调试器。要获取更多信息,请参考6.1.2节“调试类型”。
16
4
SizeOfData
调试数据(不包括调试目录自己)的大小。
20
4
AddressOfRawData
当被加载时调试数据相对于映像基址的偏移地址。
24
4
PointerToRawData
指向调试数据的文件指针。
6.1.2调试类型
为调试目录项的Type域定义了如下值:

常量
描述
IMAGE_DEBUG_TYPE_UNKNOWN
0
未知值,全部工具均忽略此值。
IMAGE_DEBUG_TYPE_COFF
1
COFF 调试信息(行号信息、符号表和字符串表)。文件头中也有相关域指向这种类型的调试信息。
IMAGE_DEBUG_TYPE_CODEVIEW
2
Visual C++ 调试信息。
IMAGE_DEBUG_TYPE_FPO
3
帧指针省略(FPO)信息。这种信息告诉调试器如何解释非标准栈帧,这种帧将EBP寄存器用于其它目的而不是做为帧指针。
IMAGE_DEBUG_TYPE_MISC
4
DBG 文件的位置。
IMAGE_DEBUG_TYPE_EXCEPTION
5
.pdata 节的副本。
IMAGE_DEBUG_TYPE_FIXUP
6
保留。
IMAGE_DEBUG_TYPE_OMAP_TO_SRC
7
从通过代码重排后的映像中的RVA到原映像中的RVA的映射。
IMAGE_DEBUG_TYPE_OMAP_FROM_SRC
8
从原映像中的RVA到通过代码重排后的映像中的RVA的映射。
IMAGE_DEBUG_TYPE_BORLAND
9
保留,供 Borland 公司使用。
IMAGE_DEBUG_TYPE_RESERVED10
10
保留。
IMAGE_DEBUG_TYPE_CLSID
11
保留。
 
若是Type域被设置为IMAGE_DEBUG_TYPE_FPO,那么原始的调试数据是一个数组,它的每一个元素都描述了一个函数的栈帧。即便调试类型为FPO,也不是映像文件中的每一个函数都必须有相应的FPO信息。没有相应FPO信息的那些函数的栈帧被看成正常的栈帧对待。FPO信息的格式以下:
#define FRAME_FPO   0
#define FRAME_TRAP 1
#define FRAME_TSS   2
 
typedef struct _FPO_DATA {
    DWORD       ulOffStart;            // 函数代码第一个字节的偏移
    DWORD       cbProcSize;            // 函数代码所占的字节数
    DWORD       cdwLocals;             // 局部变量所占字节数除以 4
    WORD        cdwParams;             // 参数所占字节数除以 4
 
    WORD        cbProlog : 8;          // 函数 prolog 代码所占字节数
    WORD        cbRegs   : 3;          // 保存的寄存器数
    WORD        fHasSEH : 1;          // 若是函数中有 SEH 此值为 TRUE
    WORD        fUseBP   : 1;          // 若是 EBP 寄存器已经被分配 此值为 TRUE
    WORD        reserved : 1;          // 保留供未来使用
    WORD        cbFrame : 2;          // 帧类型
} FPO_DATA;
6.1.3 .debug$F仅适用于目标文件
Visual C++ 7.0 及其后续版本中 这个节中的数据已经被保存在 .debug$S 一组更详尽的数据取代。
目标文件能够包含内容为一个或多个FPO_DATA记录(帧指针省略信息)的.debug$F 节。要获取更多信息,请参考6.1.2节“调试类型”中的“ IMAGE_DEBUG_TYPE_FPO ”。
连接器可以识别这些.debug$F 记录。若是指定要生成调试信息的话,连接器根据函数的RVA将相应的FPO_DATA记录排序并分别为它们生成一个调试目录项。
编译器不该该为具备标准帧格式的过程生成FPO记录。
6.1.4 .debug$S节(仅适用于目标文件)
这个节中包含的是Visual C++调试信息(符号信息)。
6.1.5 .debug$P节(仅适用于目标文件)
这个节中包含的是Visual C++调试信息(预编译信息)。它们是在全部使用由这个目标文件生成的预编译头编译生成的目标文件之间共享的类型信息。
6.1.6 .debug$T节(仅适用于目标文件)
这个节中包含的是Visual C++调试信息(类型信息)。
6.1.7连接器对Microsoft调试信息的支持
为了支持调试信息,连接器须要:
·         收集 .debug$F debug$S .debug$P .debug$T 这些 节中 全部 相关的调试数据。
·         将这些数据连同连接器生成的调试信息综合处理,生成一个PDB文件,同时建立一个指向这个文件的调试目录项。
6.2 .drectve节(仅适用于目标文件)
若是在节头中将一个节设置了IMAGE_SCN_LNK_INFO标志,而且这个节被命名为.drectve,那么它就是一个指令节。连接器在处理完其中的信息后就会移除这个节,所以它并不会出如今连接生成的映像文件中。
.drectve 节由ANSI格式或UTF-8格式的文本字符串组成。若是UTF-8字节顺序标记( BOM ,由0xEF、0xBB和0xBF组成的三字节前缀 )不存在,那么指令字符串就被看成ANSI字符串。指令字符串是由空格分隔的一串连接器选项。每一个选项包括一个连字符、选项名称以及相应的属性。若是某个选项包含空格,必须用双引号将整个选项括起来。 .drectve 节必定不能有重定位或行号信息。
6.3 .edata节(仅适用于映像文件)
导出数据节被命名为.edata,它包含的是与其它映像经过动态连接能够访问的符号相关的信息。导出符号一般出如今DLL中,但DLL也能够导入符号。
下表描述了导出节的通常结构。其中提到的各类表一般都是按下表中所示的顺序在文件中连续分布的(尽管这并非必须的)。只须要导出目录表和导出地址表这两个表就能够将序数做为导出符号导出。(序数是一个导出符号,能够把它做为导出地址表中的索引直接引用。)导出名称指针表、导出序数表和导出名称表的存在都是为了支持使用导出名称。
表名
描述
导出目录表
一个只有一行的表(与调试目录不一样)。它给出了其它各类导出表的位置和大小。
导出地址表
一个由导出符号的RVA组成的数组。它们是导出的函数和数据在可执行代码节和数据节内的实际地址。其它映像文件能够经过使用这个表的索引(序数)来导入符号,或者若是定义了一个与序数对应的公用名称的话,也能够用这个公用名称来导入符号。
导出名称指针表
一个由指向导出符号名称的指针组成的数组,按升序排列。
导出序数表
一个由对应于导出名称指针表中各个成员的序数组成的数组。它们的对应是经过位置来体现的,所以导出名称指针表与导出序数表成员数目必须相同。每一个序数都是导出地址表的一个索引。
导出名称表
一系列以NULL结尾的ASCII码字符串。导出名称指针表中的成员都指向这个区域。它们都是公用名称,符号导入与导出就是经过它们。这些公用名称并不须要与映像文件内部使用的私有名称相同。
 
当其它映像文件经过名称导入符号时,Win32加载器经过导出名称指针表来搜索匹配的字符串。若是找到,它就查找导出序数表中相应的成员(也就是说,将找到的导出名称指针表的索引做为导出序数表的索引来使用)来获取与导入符号相关联的序数。获取的这个序数是导出地址表的索引,这个索引对应的元素给出了所需符号的实际位置。每一个导出符号均可以经过序数进行访问。
当其它映像文件经过序数导入符号时,就再也不须要经过导出名称指针表来搜索匹配的字符串了。所以直接使用序数效率会更高。可是导出名称容易记忆,它不须要用户记住各个符号在表中的索引。
6.3.1导出目录表
导出目录表是导出符号信息的开始部分,它描述了导出符号信息中其他部分的内容。导出目录表包含了有关将导入符号解析为相应入口点地址的信息。
偏移
大小
描述
0
4
Export Flags
保留,必须为0。
4
4
Time/Date Stamp
导出数据被建立的日期和时间。
8
2
Major Version
主版本号。用户能够自行设置主版本号和次版本号。
10
2
Minor Version
次版本号。
12
4
Name RVA
包含这个DLL名称的ASCII码字符串相对于映像基址的偏移地址。
16
4
Ordinal Base
映像中导出符号的起始序数值。这个域指定了导出地址表的起始序数值。它一般被设置为1。
20
4
Address Table Entries
导出地址表中元素的数目。
24
4
Number of Name Pointers
导出名称指针表中元素的数目。它同时也是导出序数表中元素的数目。
28
4
Export Address Table RVA
导出地址表相对于映像基址的偏移地址。
32
4
Name Pointer RVA
导出名称指针表相对于映像基址的偏移地址。它的大小由Number of Name Pointers域给出。
36
4
Ordinal Table RVA
导出序数表相对于映像基址的偏移地址。
6.3.2导出地址表
导出地址表包含导出函数、导出数据以及绝对符号的地址。序数值是做为导出地址表的索引来使用的。
导出地址表的每个元素都是一个域,其格式为下表所述的两种格式之一。若是指定的地址不是位于导出节(其地址和长度由可选文件头给出)中,那么这个域就是一个Export RVA,这个地址就是导出符号在代码或数据中的实际地址;不然这个域是一个Forwarder RVA,它给出了一个位于其它DLL中的符号的名称。
偏移
大小
描述
0
4
Export RVA
当加载进内存时,导出符号相对于映像基址的偏移地址。例如导出函数的地址。
0
4
Forwarder RVA
这是指向导出节中一个以NULL结尾的ASCII码字符串的指针。这个字符串必须位于Export Table(导出表)数据目录项给出的范围以内。要获取更多信息,请参考3.4.3节“可选文件头中的数据目录(仅适用于映像文件)”。这个字符串给出了导出符号所在DLL的名称以及导出符号的名称(例如“MYDLL.expfunc”),或者DLL的名称以及导出符号的序数值(例如“MYDLL.#27”)。
 
Forwarder RVA 导出了其它映像中定义的符号,使它看起来好像是当前映像导出的同样。所以对于当前映像来讲,这个符号同时既是导入符号又是导出符号。
例如对于Windows XP系统中的Kernel32.dll文件来讲,它导出的“HeapAlloc”被转发到“ NTDLL.RtlAllocateHeap ”。这样就容许应用程序使用Windows XP系统中的Ntdll.dll模块而不须要实际包含任何相关的导入信息。应用程序的导入表只与Kernel32.dll有关。这样应用程序就不是特定于Windows XP,它能够运行于任何Win32系统之上。
6.3.3导出名称指针表
导出名称指针表是由导出名称表中的字符串的地址(RVA)组成的数组。每一个地址都是相对于映像基址的32位指针。它们按词法顺序排列以便进行二进制搜索。
只有当导出名称指针表中包含指向某个导出名称的指针时,这个导出名称才算被定义。
6.3.4导出序数表
导出序数表是由导出地址表的索引组成的一个数组,每一个序数长16位。可是这个序数是移码形式,相应的偏移量由导出目录表中的Ordinal Base域给出。换句话说,必须从序数值中减去Ordinal Base域的值获得的才是导出地址表真正的索引。
导出名称指针表和导出序数表是两个并列的数组,将它们分开是为了使它们能够分别按照各自的天然边界(前者是4个字节,后者是2个字节)对齐。在进行操做时,这两个表等效于一个表(在这个等效的新表中,这两个表分别至关于新表中的两列),由导出名称指针这一列给出公共(导出)符号的名称,而由导出序数这一列给出这个导出符号对应的序数。导出名称指针表的成员和导出序数表的成员经过同一个索引相关联。
所以,当在导出名称指针表中搜索并找到匹配字符串的索引为i 时,查找符号对应地址的算法以下:
i = Search_ExportNamePointerTable (ExportName);
ordinal = ExportOrdinalTable [i];
SymbolRVA = ExportAddressTable [ordinal - OrdinalBase];
6.3.5导出名称表
导出名称表包含的是导出名称指针表实际指向的字符串。这个表中的字符串都是公用名称,其它映像能够经过它们导入这些符号。这些公用导出名称并不须要与这些符号所在的映像文件和源代码中的私有符号名称相同,尽管它们能够相同。
每一个导出符号都有一个相应的序数值,这个值是导出地址表的索引(加上 Ordinal Base 域的值)。可是使用导出名称(来导出符号)是可选的。能够所有导出符号都有导出名称,也能够部分导出符号有导出名称,也能够所有导出符号都没有导出名称。对于那些有导出名称的导出符号来讲,导出名称指针表和导出序数表中相应的项配合起来使每一个名称与一个序数相关联。
导出名称表的结构就是长度可变的一系列以NULL结尾的ASCII码字符串。
6.4.idata
全部导入符号的映像文件,实际上几乎包括全部的可执行(EXE)文件,都有.idata节。文件中导入信息的典型布局以下:
目录表
 
 
 
空目录项
 
DLL1的导入查找表
 
空表项
 
DLL2的导入查找表
 
空表项
 
DLL3的导入查找表
 
空表项
 
提示/名称表
 
图3. 典型的导入节布局
6.4.1导入目录表
导入目录表是导入信息的开始部分,它描述了导入信息中其他部分的内容。导入目录表包含地址信息,这些地址信息用来修正对DLL映像中的相应函数的引用。导入目录表是由导入目录项组成的数组,每一个导入目录项对应着一个导入的DLL。最后一个导入目录项是空的(所有域的值都为NULL),用来指明目录表的结尾。
每一个导入目录项的格式以下:
偏移
大小
描述
0
4
Import Lookup Table RVA (Characteristics)
导入查找表的RVA。这个表包含了每个导入符号的名称或序数。(这个域在Winnt.h文件中的名称是“Characteristics”,但已经名存实亡了。)
4
4
Time/Date Stamp
这个域一直被设置为0,直到映像被绑定。当映像被绑定以后,这个域被设置为这个DLL的日期/时间戳。
8
4
Forwarder Chain
第一个转发项的索引。
12
4
Name RVA
包含DLL名称的ASCII码字符串相对于映像基址的偏移地址。
16
4
Import Address Table RVA (Thunk Table)
导入地址表的RVA。这个表的内容与导入查找表的内容彻底同样,直到映像被绑定。
6.4.2导入查找表
导入查找表是由长度为32位(PE32)或64位(PE32+)的数字组成的数组。其中的每个元素都是位域,其格式以下表所示。在这种格式中,位31(PE32)或位63(PE32+)是最高位。这些项描述了从给定的DLL导入的全部符号。最后一个项被设置为0(NULL),用来指明表的结尾。
大小
位域
描述
31/63
1
Ordinal/Name Flag
若是这个位为1,说明是经过序数导入的。不然是经过名称导入的。测试这个位的掩码为0x80000000(PE32)或0x8000000000000000(PE32+)。
15-0
16
Ordinal Number
序数值(16位长)。只有当Ordinal/Name Flag域为1(即经过序数导入)时才使用这个域。位30-15(PE32)或62-15(PE32+)必须为0。
30 - 0
31
Hint/Name Table RVA
提示/名称表项的RVA(31位长)。只有当Ordinal/Name Flag域为0(即经过名称导入)时才使用这个域。对于PE32+来讲,位62-31必须为0。
 
6.4.3提示/名称表
一个提示/名称表就能知足整个导入节的须要。提示/名称表中的每个元素结构以下:
偏移
大小
描述
0
2
Hint
导出名称指针表的索引。当搜索匹配字符串时首选使用这个值。若是匹配失败,再在DLL的导出名称指针表中进行二进制搜索。
2
可变
Name
包含导入符号名称的ASCII码字符串。这个字符串必须与DLL导出的公用名称匹配。同时这个字符串区分大小写而且以NULL结尾。
*
0 1
Pad
为了让提示/名称表的下一个元素出如今偶数地址,这里可能须要填充0个或1个NULL字节。
6.4.4导入地址表
导入地址表的结构和内容与导入查找表彻底同样,直到文件被绑定。在绑定过程当中,用导入符号的32位(PE32)或64位(PE32+)地址覆盖导入地址表中的相应项。这些地址是导入符号的实际内存地址,尽管技术上仍把它们称为“虚拟地址”。加载器一般会处理绑定。
6.5 .pdata
.pdata 节是由用于异常处理的函数表项组成的数组。可选文件头中的 Exception Table (异常表)域指向它。在将它们放进最终的映像文件以前,这些项必须按函数地址(下列每一个结构的第一个域)排序。下面描述了函数表项的三种格式,使用哪种取决于目标平台。
对于32位的MIPS映像来讲,其函数表项格式以下:
偏移
大小
描述
0
4
Begin Address
相应函数的VA。
4
4
End Address
函数结尾的VA。
8
4
Exception Handler
指向要执行的异常处理程序的指针。
12
4
Handler Data
指向要传递给异常处理程序的附加数据的指针。
16
4
Prolog End Address
函数prolog代码结尾的VA。
 
对于 ARM PowerPC SH3 SH4 Windows CE 平台来讲,其函数表项格式以下:
偏移
大小
描述
0
4
Begin Address
相应函数的VA。
4
8
Prolog Length
函数prolog代码包含的指令数。
4
22
Function Length
函数代码包含的指令数。
4
1
32-bit Flag
若是此位为1,代表函数由32位指令组成。不然,函数由16位指令组成。
4
1
Exception Flag
若是此位为1,代表存在用于此函数的异常处理程序;不然,不存在异常处理程序。
 
对于x64和Itanium平台来讲,其函数表项格式以下:
偏移
大小
描述
0
4
Begin Address
相应函数的RVA。
4
4
End Address
函数结尾的RVA。
8
4
Unwind Information
用于异常处理的展开( Unwind )信息的RVA。
6.6 .reloc节(仅适用于映像文件)
基址重定位表包含了映像中全部须要重定位的内容。可选文件头中的数据目录中的Base Relocation Table(基址重定位表)域给出了基址重定位表所占的字节数。要获取更多信息,请参考3.4.3节“可选文件头中的数据目录(仅适用于映像文件) ”。基址重定位表被划分红许多块,每一块表示一个4K页面范围内的基址重定位信息,它必须从32位边界开始。
加载器不须要处理由连接器解析的基址重定位信息,除非映像不能被加载到PE文件头中指定的映像基地址处。
6.6.1基址重定位块
个基址重定位块的开头都是以下结构: