MZ
可执行文件格式 |
---|
Microsoft |
*nix |
MS-DOS EXE格式,以MZ签名开头(微软工程师马克·兹比科夫斯基-Mark Zbykowski的首字母缩写),是在MS-DOS 2.0中引入的(1.0版仅采用简单的COM格式)。 它被设计成在实模式下运行的可重新定位的可执行文件。 因此,只有DOS和Windows 9x可以本机使用这种格式,但通过几个自由的DOS模拟器(例如DOSBox),可实现在各种操作系统(如Linux、Amiga、Windows NT等)下运行。 虽然MZ可执行文件可以独立存在,但它们嵌入在所有NE、LE和PE可执行文件中,通常作为以上文件的存根,因此以上文件在DOS下运行时,它们会显示:
This program cannot be run in MS-DOS mode.
所以也可以使用它们,以便单个可执行文件可以为同一应用程序提供两个入口(例如,一个用于DOS,一个用于Windows)。 如果从命令行提示符启动程序,Windows 9x将运行MZ可执行文件,如果正常启动,则运行PE可执行文件。 在引导加载程序(boot loaders)中,它们可以帮助提供一个DOS版本,尤其是因为UEFI需要PE格式,而其中刚好可以包含一个MZ可执行文件。
MZ文件结构
MZ可执行文件仅由两个结构组成:文件头和重定位表(relocation table)。 文件头后面是程序映像,文件头如下所示:
偏移量 | 字段 | 大小 | 描述 | |
---|---|---|---|---|
0 | 0x00 | 签名(Signature) | word | 0x5A4D(ASCII表示“M”和“Z”) |
2 | 0x02 | Extra bytes | word | 最后一页中的字节数。 |
4 | 0x04 | Pages | word | 所有页的数量。 |
6 | 0x06 | Relocation items | word | 重新定位表中的条目数。 |
8 | 0x08 | Header size | word | 文件头占用的段落数。 其实它可以是任何值,因为加载程序只使用它来查找实际可执行数据的起始位置。 它可能比“标准”字段的头文件占用的空间大,这样如果您想包含自己的文件头元数据,甚至将重定位表放在那里,或者将其用于任何其他目的,都可以使用标准头以后的空间。 |
10 | 0x0A | Minimum allocation | word | 程序必要的段落数,不包括PSP和程序映像。(译者注:PSP指Program Segment Prefix) 如果没有足够大的自由块,加载将停止。 |
12 | 0x0C | Maximum allocation | word | 程序请求的段落数。 如果没有足够大的空闲块,则分配最大的空闲块。 |
14 | 0x0E | Initial SS | word | SS的可重定位段地址。 |
16 | 0x10 | Initial SP | word | SP的初始值。 |
18 | 0x12 | 校验和(Checksum) | word | 当和文件中所有其他word求和时,结果应为零。 |
20 | 0x14 | Initial IP | word | IP的初始值。 |
22 | 0x16 | Initial CS | word | CS的可重定位段地址。 |
24 | 0x18 | Relocation table | word | 到重定位表的(绝对)偏移量。 |
26 | 0x1A | Overlay | word | 用于Overlay管理的值。如果为零,则这是主可执行文件。 |
28 | 0x1C | Overlay information | N/A | 文件有时包含用于主程序Overlay管理的额外信息。 |
段落大小为16字节。页面(或块)的长度为512字节。
如果minimum 和 maximum allocation字段都清除了,MS-DOS将尝试在内存中尽可能高地加载可执行文件。 否则,在内存不足时,映像将加载到256字节PSP结构的正上方。
重定位
在将可执行文件加载到内存中之后,程序加载器将遍历重定位表中的每个条目。 对于每个重定位条目,加载器将起始段地址添加到segment:offset对指向的字值中。 因此,例如,重新定位条目0001:001A将使加载程序将起始段地址添加到程序数据中偏移量1*0x10+0x1A=0x2A处的值。
重定位表中的每个指针如下所示:
偏移量 | 字段 | 大小 | 描述 | |
---|---|---|---|---|
0 | 0x00 | Offset | word | 在提供的区段内重新安置的偏移量。 |
2 | 0x02 | Segment | word | 相对于加载段地址的重新定位段。 |
CS和SS寄存器以类似的方式重新定位。
初始程序状态
- ES和DS寄存器都指向包含PSP结构的段。
- CS等于文件头中指定的值,通过向其添加起始段地址重新定位。
- IP等于文件头中指定的值。请注意,与COM可执行文件不同,MZ程序不会在偏移量0x100处启动。
- SS等于文件头中指定的值,重新定位,就像CS一样。
- SP等于文件头中指定的值。
- 如果PSP中的第一个FCB具有有效的驱动器标识符,则AL为0x00,否则为0xFF。
- AH与AL相同,但适用于PSP中的第二个FCB。
- 所有其他寄存器可以设置为0,也可以不设置为0。你应该认为它们都还没有定义。
PE扩展
随着PE可执行文件的出现,微软在MZ头文件中添加了一些项目,在WinNT.h中进行了定义
偏移量 | 字段 | 大小 | 描述 | |
---|---|---|---|---|
28 | 0x1C | Reserved | qword | |
36 | 0x24 | OEM identifier | word | 按名称定义,但未提供其他信息;通常为零 |
38 | 0x26 | OEM info | word | 按名称定义,但未提供其他信息;通常为零 |
40 | 0x28 | Reserved | 20 bytes | |
60 | 0x3C | PE header start | dword | PE头的起始地址 |