所以.exe文件是一个可以被windows执行的文件,但是它到底包含了什么呢?处理器特定的汇编语言?或者是某种被windows识别的中间语句,它将它转换为特定处理器的汇编?windows在“执行”这个文件时到底做了什么?
dpiehjr41#
MSDN有一篇文章“An In-Depth Look into the Win32 Portable Executable File Format”,描述了可执行文件的结构。基本上,.exe包含几个数据blob和关于如何将它们加载到内存中的指令。其中一些部分恰好包含可以执行的机器代码(其他部分包含程序数据、资源、重定位信息、导入信息等)我建议你得到一份Windows Internals的副本,以获得运行exe时会发生什么的完整描述。对于本机可执行文件,机器代码是平台特定的。.exe的标头指示.exe适用的平台。运行native .exe时,会发生以下情况(非常简单):
托管可执行文件包含MSIL(Microsoft中间语言),可以对其进行编译,以便它们可以针对CLR支持的任何CPU。我不太熟悉CLR加载器的内部工作原理(最初运行什么本机代码来 Boot CLR并开始解释MSIL)-也许其他人可以详细说明这一点。
jrcvhitl2#
我可以告诉你.exe文件的前两个字节包含什么- 'MZ'。我是说MZ这几个字。它实际上代表:马克·兹比科夫斯基设计exe文件格式的家伙。http://en.wikipedia.org/wiki/Mark_Zbikowski
lf5gs5x23#
1和0!This wikipedia link将给予您提供用于Windows应用程序的可移植可执行文件格式的所有信息。
rmbxnbpk4#
EXE文件实际上是一种称为可移植可执行文件的文件类型。它包含二进制数据,可以由处理器读取和执行(本质上是x86指令)。实际的可执行代码位于名为.text的部分中,并存储为机器指令(特定于处理器)。此代码(以及.EXE的其他部分)被放入内存中,CPU将发送给它,并在那里开始执行。(注意实际上有更多的接口;这是简化的解释)。
.text
1cklez4t5#
我只能为旧版DOS. EXE回答这个问题。Windows版本(便携式EXE)实质上涉及更多,需要更多的解释和理解。所以,我会把这个留给其他人。8086是为DOS EXE设计的,它使用一个名义上为32位的地址,把它的存储器组织成2个段,每个段最多2个字节,地址的组成部分分别被称为“段”和“偏移量”。具有段S和偏移量O的地址将被写为S:O。它的设计思想是将单个源代码文件编译成单个段,文件内访问只使用地址的“偏移量”部分,因此只有对全局对象的文件间访问才需要完整的地址。地址通过Map到2²物理空间来展平,使得物理地址为2 ×段+偏移量;即,使得段S+1的地址0在段S中的地址2处的“段落”边界上重叠。在大多数情况下,不需要知道展平的其他细节,并且通常不会在程序中显式使用,但在EXE文件的布局中是默认的。因此,EXE文件的格式就是在“后期展平”阶段看到的程序映像。这个8086架构在80186和80286之前基本保持不变。在80386中,分段架构被占用并重新调整了用途,尽管在有限的上下文中,旧的安排保持不变。这也是从DOS到Windows EXE文件格式的转换发生的地方。EXE文件包含包含代码和初始化数据的段的实际二进制映像。图像本身从段0开始,地址为0,这些段在文件中展开并展平。当程序被加载到内存中时,“加载程序”将在任何内存段中或其后有足够空闲空间的位置开始设置它。由于8086的机器语言引用了绝对地址,因此程序内的绝对地址必须在EXE文件中列出,以便加载程序可以进入程序映像并进行适当的调整。因此,如果一个程序要在段S处加载,并且在位置S:O处的程序内部的引用是对段S的引用(即,如果在程序映像中从位置S:O开始存储的2字节字是S),则它将把它的值调整为S +S。这些项目称为“重定位”,而包含它们的表称为“重定位表”。它们的存在和使用是EXE文件格式的主要特点。调整完成后,它将在EXE文件指定的位置设置初始堆栈。这包括堆栈段及其大小。在8086上,堆栈指针通过“推入”向下移动,通过“弹出”向上移动,因此堆栈指针的初始值位于堆栈段的末尾。因此,EXE文件包含SS:SP(堆栈段+堆栈指针)的初始值。然后,它将跳转到EXE文件为其指定的入口点。因此,EXE文件还包括CS:IP的初始值(代码段+指令指针)。它还包括对程序数据的最小和最大大小请求,尽管我不确定加载器如何处理这些信息,除了确定程序是否可以加载。同样,它也有一个校验和,我不认为这是甚至尊重,以及一个“覆盖”数字,以区分主程序和子程序(可能是Windows DLL的前身)。EXE文件的强制部分由14个2字节的字组成。请注意,8086中的所有2字节字都占用2个连续的8位存储器地址,首先是低8位,然后是高8位。在下面的描述中,我将使用十六进制数字来表示所有内容,因为这是最直接地与需要描述的内容相协调的。然后,通过它们的地址将强制字标记为W 00、W 02、W 04、W 06、W 08、W 0a、W 0 c、W 0 e、W10、W12、W14、W16、W18、W1 a,刚刚描述的信息被布置为:(1)入口点- CS:IP = W16:W14,(2)堆栈段- SS:SP = W 0 e:W10,(3)重定位表位置W18(=可移植EXE文件格式规范中的RB)在EXE文件中的位置,以及重定位次数W 06、(4)代码映像文件中的起始点位于:2 ×W08,(5)覆盖编号是W1 a,对于“主”程序是0--这是我见过的唯一用例,(6)校验和为W12,(7)程序数据的请求范围为2 × W 0a到2 × W 0 c。我所看到的W 0 c的唯一用例是将其设置为最大大小ffff。(8)如果W 02> 0,则程序文件的大小为2(W 04 - 1)+W 02,否则为2 W 04,如果W 02 = 0,则
(9)W 00 = 5a 4d是文件类型“签名”,其以地址的递增顺序列出为4d和5a,其(ASCII)是字母“M”和“Z”,代表程序员马克·兹比科夫斯基,他可能是微软早期做所有肮脏工作的人,他在20世纪70年代与比尔·盖茨在车库里的谈话和争论,我可以看到和听到的回声,当我看他们的一些老程序的二进制文件。重定位表的每一项都包含要重定位的项的S:O地址,首先列出O,然后是S。因此,重定位表的大小(以字节为单位)是其条目数的4倍。在实际程序的示例中,002 b条目(或00 ac字节)的重定位表位于EXE文件中的001 e-00 ca处。程序映像的大小为548 e字节,其中段被展平并放置在文件0200- 548 d处。堆栈初始化为SS:SP = 06 c1:0800,入口点为CS:IP = 0000:05 d 0。数据请求范围为2190-ffff 0字节,校验和为e3 d8。因此,强制性16位字的布局是W 00 = 5a 4d,(W02,W04)=(008e,002b),W06 = 002b,W08 = 0020,(W0a,W0c)=(0219,ffff),(W0e,W10)=(06cl,0800),W12 = e3d8,(W14,W16)=(05d0,0000),W18 = 001e,W1a = 0000作为一个字节序列,它读作:4d,5a,8e,00,2b,00,2b,00,20,00,19,02,ff,ff,c1,06,00,08,d8,e3,d0,05,00,00,1e,00,00,00在文件位置001 c-001 d处存在覆盖空洞,因为重定位在文件位置001 e处开始。重定位表位于文件位置001 e-00 c9,并且具有如下形式,作为字节序列:22,00,00,00,2e,00,00,00,...63、39、35、01其由用于程序映像中的地址0000:0022、0000:002 e、...、0135:3963的字0022、0000、002 e、0000、...、3963、0135组成。重定位中列出的几个段,包括0000、0135、04 d 0、04 fe、0500,这是一种可以获得有关如何将代码映像划分为段的信息的方法-EXE文件不会显式地拼出各个段,因为它们已经被展平了。从文件位置00 ca到01 ff存在另一个覆盖间隙,并且代码图像从文件位置0200开始直到文件的548 d结束。刚才提到的实际段Map在段0000的0200- 154 f1550-4段0135的效应段04 d 0的4f 00 - 51 df段04 fe的51 e0 - 51 ff段0500的5200- 548 d假设这些是节目中仅有的片段。当程序被覆盖到内存中时,在重定位完成后,它将被放置在物理内存中第一个可用地址的0000- 528 d处。因此,例如,如果它被加载器重新定位到段077 a(我的DosBox版本),那么加载器必须首先进行调整。因此,例如,在代码图像0000:0022中列出的单词(并且位于文件0222-0223中)包含单词0135(指示段0135),并且必须提升到0135+ 077 a = 08 af。作为重定位过程的一部分,段本身同样从0000、0135、04 d 0、04 fe、0500(和用于堆叠的06 cl)分别提升到077 a、08 af、0 c4 a、0 c78、0 c7 a(和用于堆叠的0 e3 b)。
5条答案
按热度按时间dpiehjr41#
MSDN有一篇文章“An In-Depth Look into the Win32 Portable Executable File Format”,描述了可执行文件的结构。
基本上,.exe包含几个数据blob和关于如何将它们加载到内存中的指令。其中一些部分恰好包含可以执行的机器代码(其他部分包含程序数据、资源、重定位信息、导入信息等)
我建议你得到一份Windows Internals的副本,以获得运行exe时会发生什么的完整描述。
对于本机可执行文件,机器代码是平台特定的。.exe的标头指示.exe适用的平台。
运行native .exe时,会发生以下情况(非常简单):
托管可执行文件包含MSIL(Microsoft中间语言),可以对其进行编译,以便它们可以针对CLR支持的任何CPU。我不太熟悉CLR加载器的内部工作原理(最初运行什么本机代码来 Boot CLR并开始解释MSIL)-也许其他人可以详细说明这一点。
jrcvhitl2#
我可以告诉你.exe文件的前两个字节包含什么- 'MZ'。我是说MZ这几个字。
它实际上代表:马克·兹比科夫斯基设计exe文件格式的家伙。
http://en.wikipedia.org/wiki/Mark_Zbikowski
lf5gs5x23#
1和0!
This wikipedia link将给予您提供用于Windows应用程序的可移植可执行文件格式的所有信息。
rmbxnbpk4#
EXE文件实际上是一种称为可移植可执行文件的文件类型。它包含二进制数据,可以由处理器读取和执行(本质上是x86指令)。实际的可执行代码位于名为
.text
的部分中,并存储为机器指令(特定于处理器)。此代码(以及.EXE的其他部分)被放入内存中,CPU将发送给它,并在那里开始执行。(注意实际上有更多的接口;这是简化的解释)。1cklez4t5#
我只能为旧版DOS. EXE回答这个问题。Windows版本(便携式EXE)实质上涉及更多,需要更多的解释和理解。所以,我会把这个留给其他人。
8086是为DOS EXE设计的,它使用一个名义上为32位的地址,把它的存储器组织成2个段,每个段最多2个字节,地址的组成部分分别被称为“段”和“偏移量”。具有段S和偏移量O的地址将被写为S:O。
它的设计思想是将单个源代码文件编译成单个段,文件内访问只使用地址的“偏移量”部分,因此只有对全局对象的文件间访问才需要完整的地址。
地址通过Map到2²物理空间来展平,使得物理地址为2 ×段+偏移量;即,使得段S+1的地址0在段S中的地址2处的“段落”边界上重叠。在大多数情况下,不需要知道展平的其他细节,并且通常不会在程序中显式使用,但在EXE文件的布局中是默认的。因此,EXE文件的格式就是在“后期展平”阶段看到的程序映像。
这个8086架构在80186和80286之前基本保持不变。在80386中,分段架构被占用并重新调整了用途,尽管在有限的上下文中,旧的安排保持不变。这也是从DOS到Windows EXE文件格式的转换发生的地方。
EXE文件包含包含代码和初始化数据的段的实际二进制映像。图像本身从段0开始,地址为0,这些段在文件中展开并展平。
当程序被加载到内存中时,“加载程序”将在任何内存段中或其后有足够空闲空间的位置开始设置它。由于8086的机器语言引用了绝对地址,因此程序内的绝对地址必须在EXE文件中列出,以便加载程序可以进入程序映像并进行适当的调整。
因此,如果一个程序要在段S处加载,并且在位置S:O处的程序内部的引用是对段S的引用(即,如果在程序映像中从位置S:O开始存储的2字节字是S),则它将把它的值调整为S +S。
这些项目称为“重定位”,而包含它们的表称为“重定位表”。它们的存在和使用是EXE文件格式的主要特点。
调整完成后,它将在EXE文件指定的位置设置初始堆栈。这包括堆栈段及其大小。在8086上,堆栈指针通过“推入”向下移动,通过“弹出”向上移动,因此堆栈指针的初始值位于堆栈段的末尾。因此,EXE文件包含SS:SP(堆栈段+堆栈指针)的初始值。
然后,它将跳转到EXE文件为其指定的入口点。因此,EXE文件还包括CS:IP的初始值(代码段+指令指针)。
它还包括对程序数据的最小和最大大小请求,尽管我不确定加载器如何处理这些信息,除了确定程序是否可以加载。同样,它也有一个校验和,我不认为这是甚至尊重,以及一个“覆盖”数字,以区分主程序和子程序(可能是Windows DLL的前身)。
EXE文件的强制部分由14个2字节的字组成。请注意,8086中的所有2字节字都占用2个连续的8位存储器地址,首先是低8位,然后是高8位。
在下面的描述中,我将使用十六进制数字来表示所有内容,因为这是最直接地与需要描述的内容相协调的。
然后,通过它们的地址将强制字标记为W 00、W 02、W 04、W 06、W 08、W 0a、W 0 c、W 0 e、W10、W12、W14、W16、W18、W1 a,刚刚描述的信息被布置为:
(1)入口点- CS:IP = W16:W14,
(2)堆栈段- SS:SP = W 0 e:W10,
(3)重定位表位置W18(=可移植EXE文件格式规范中的RB)在EXE文件中的位置,以及重定位次数W 06、
(4)代码映像文件中的起始点位于:2 ×W08,
(5)覆盖编号是W1 a,对于“主”程序是0--这是我见过的唯一用例,
(6)校验和为W12,
(7)程序数据的请求范围为2 × W 0a到2 × W 0 c。我所看到的W 0 c的唯一用例是将其设置为最大大小ffff。
(8)如果W 02> 0,则程序文件的大小为2(W 04 - 1)+W 02,否则为2 W 04,如果W 02 = 0,则
(9)W 00 = 5a 4d是文件类型“签名”,其以地址的递增顺序列出为4d和5a,其(ASCII)是字母“M”和“Z”,代表程序员马克·兹比科夫斯基,他可能是微软早期做所有肮脏工作的人,他在20世纪70年代与比尔·盖茨在车库里的谈话和争论,我可以看到和听到的回声,当我看他们的一些老程序的二进制文件。
重定位表的每一项都包含要重定位的项的S:O地址,首先列出O,然后是S。因此,重定位表的大小(以字节为单位)是其条目数的4倍。
在实际程序的示例中,002 b条目(或00 ac字节)的重定位表位于EXE文件中的001 e-00 ca处。程序映像的大小为548 e字节,其中段被展平并放置在文件0200- 548 d处。堆栈初始化为SS:SP = 06 c1:0800,入口点为CS:IP = 0000:05 d 0。数据请求范围为2190-ffff 0字节,校验和为e3 d8。
因此,强制性16位字的布局是W 00 = 5a 4d,
(W02,W04)=(008e,002b),
W06 = 002b,
W08 = 0020,
(W0a,W0c)=(0219,ffff),
(W0e,W10)=(06cl,0800),
W12 = e3d8,
(W14,W16)=(05d0,0000),
W18 = 001e,
W1a = 0000
作为一个字节序列,它读作:4d,5a,8e,00,2b,00,2b,00,20,00,19,02,ff,ff,c1,06,00,08,d8,e3,d0,05,00,00,1e,00,00,00
在文件位置001 c-001 d处存在覆盖空洞,因为重定位在文件位置001 e处开始。重定位表位于文件位置001 e-00 c9,并且具有如下形式,作为字节序列:
22,00,00,00,
2e,00,00,00,
...
63、39、35、01
其由用于程序映像中的地址0000:0022、0000:002 e、...、0135:3963的字0022、0000、002 e、0000、...、3963、0135组成。
重定位中列出的几个段,包括0000、0135、04 d 0、04 fe、0500,这是一种可以获得有关如何将代码映像划分为段的信息的方法-EXE文件不会显式地拼出各个段,因为它们已经被展平了。
从文件位置00 ca到01 ff存在另一个覆盖间隙,并且代码图像从文件位置0200开始直到文件的548 d结束。
刚才提到的实际段Map在
段0000的0200- 154 f
1550-4段0135的效应
段04 d 0的4f 00 - 51 df
段04 fe的51 e0 - 51 ff
段0500的5200- 548 d
假设这些是节目中仅有的片段。当程序被覆盖到内存中时,在重定位完成后,它将被放置在物理内存中第一个可用地址的0000- 528 d处。
因此,例如,如果它被加载器重新定位到段077 a(我的DosBox版本),那么加载器必须首先进行调整。因此,例如,在代码图像0000:0022中列出的单词(并且位于文件0222-0223中)包含单词0135(指示段0135),并且必须提升到0135+ 077 a = 08 af。作为重定位过程的一部分,段本身同样从0000、0135、04 d 0、04 fe、0500(和用于堆叠的06 cl)分别提升到077 a、08 af、0 c4 a、0 c78、0 c7 a(和用于堆叠的0 e3 b)。