TONT 32483 为什么有时损坏的二进制文件会令系统提示『程序太大,不能装入内存』?

原文链接:https://devblogs.microsoft.com/oldnewthing/20060130-00/?p=32483

译注:原文第一段比较长,为方便阅读,进行了手工拆分。

If you take a program and corrupt the header, or just take a large-ish file that isn’t a program at all and give it a “.exe” extension, then try to run it (Warning: Save your work first!), you will typically get the error “Program too big to fit in memory”. Why such a confusing error message? Why doesn’t it say “Corrupted program”?

随便找一个程序来,然后把它的文件头搞乱,或者干脆随便拿一个挺大的、不是应用程序的文件,并给它一个.exe的扩展名,然后尝试运行之(警告:先保存好你正在进行的工作!),通常你会得到一条错误信息:『程序太大,不能装入内存』。为什么是这么令人费解的一条错误信息呢?为什么不说是『程序已损坏』呢?

Because the program isn’t actually corrupted. Sort of.

因为从某种意义上讲,这个程序实际上并没有损坏。

A Win32 executable file begins with a so-called “MZ” header, followed by a so-called “PE” header. If the “PE” header cannot be found, then the loader attempts to load the program as a Win16 executable file, which consists of an “MZ” header followed by an “NE” header. If neither a “PE” nor an “NE” header can be found after the “MZ” header, then the loader attempts to load the program as an MS-DOS relocatable executable. If not even an “MZ” header can be found, then the loader attempt to load the program as an MS-DOS non-relocatable executable (aka “COM format” since this is the format of CP/M .COM files). In pictures:

一个 Win32 可执行文件的开头包含所谓的『MZ』文件头,紧跟着是所谓的『PE』头。如果找不到PE头,那么加载器就会尝试将程序按照 Win16 可执行文件进行读取,而 Win16 的文件头便是MZ后面跟一个NE。如果在MZ头之后既没有找到PE头,也没有找到NE头,那么加载器会尝试将程序按照MS-DOS可重定位可执行文件进行加载。如果连MZ头都没找到,那么加载器就会将其按照MS-DOS不可重定位可执行文件(也叫做COM格式,因为这是CP/M的.COM文件的格式)进行加载。总的来说就是:

MZ PE Win32
NE Win16
其它情况 MS-DOS 可重定位可执行文件
其它情况 MS-DOS 不可重定位可执行文件

Observe that no matter what path you take through the chart, you will always end up at something. There is no exit path that says “Corrupted program”. But where does “Program too big to fit in memory” come from?

很明显,根据上面表格中列出的情况,不管走哪条路最后都会到达某个终点,并且并没有哪个终点是显示『程序已损坏』这条消息的选项。话说回来,『程序太大,无法载入内存』又是怎么回事呢?

If the program header is corrupted, then various fields in the header such as those which specify the amount of memory required by the program will typically be nonsensical values. The loader sees an MS-DOS relocatable program that requires 800KB of conventional memory, and that’s where “Out of memory” comes from. An MS-DOS non-relocatable program contains no such information about memory requirements. The rule for loading non-relocatable programs is simply to load the program into a single 64KB chunk of memory and set it on its way. Therefore, a program with no “MZ” header but which is larger than 64KB in size won’t fit in the single 64KB chunk and consequently results in an “Out of memory” error.

如果某个程序的文件头损坏了,那么在文件头中的一些字段——例如指定程序所需内存数量的值通常会是一些毫无意义的数值。加载器会将其视为一个请求800KB常规内存的 MS-DOS 可重定位应用程序(译注:常规内存上限为640KB),而这就是『内存不足』消息的来源。MS-DOS 不可重定位应用程序是不包含类似所需内存数量之类的信息的,加载这类程序的路子,就是将其装入单独一段64KB内存并运行它。因此,一个没有MZ头、但是尺寸又比64KB大的程序自然无法装入64KB的内存段,由此引发了『内存不足』的错误。

And since people are certain to ask:

顺便一提吧,反正肯定会有人问:

“MZ” = the legendary Mark Zbikowski.

MZ:传奇人物 Mark Zbikowski 的缩写(译注:微软公司的元老级开发者)

“NE” = “New Executable”, back when Windows was “new”.

NE:新式可执行程序(New Executable)的缩写,那时候 Windows 还蛮『新』的。

“PE” = “Portable Executable”, because one of Windows NT’s claims to fame was its portability to architectures other than the x86.

PE:便携式可执行程序(Portable Executable)的缩写,因为 Windows NT 出名的原因之一就是其可以在 x86 平台之外的可移植性。

“LE” = “Linear Executable”, used by OS/2 and by Windows 95 device drivers.

LE:线性可执行程序(Linear Executable),由 OS/2 和 Windows 95 的驱动程序所使用。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

 剩余字数 ( Characters available )

Your comment will be available after auditing.
您的评论将在通过审核后显示。

Please DO NOT add any links in your comment, otherwise it would be identified as SPAM automatically and never be audited.
请不要在评论中插入任何链接,否则将被自动归类为垃圾评论,且永远不会被提交给博主进行复审。

*