Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 为什么.COM程序中只有一个程序段,用于程序代码和堆栈?_Assembly_Dos_X86 16_Memory Segmentation - Fatal编程技术网

Assembly 为什么.COM程序中只有一个程序段,用于程序代码和堆栈?

Assembly 为什么.COM程序中只有一个程序段,用于程序代码和堆栈?,assembly,dos,x86-16,memory-segmentation,Assembly,Dos,X86 16,Memory Segmentation,我正在研究.EXE程序和.COM程序之间的区别。 EXE对我来说是合乎逻辑的,堆栈位于与程序代码相关的另一段中(事实上,堆栈是强制的,并用.stack指示此限制),因此,当我转到插入值时​​在堆栈中(在.EXE中),使用与程序不同的段,我不会混淆这两个 例如: SP = 0400 SS = 3996 CS = 3995 IP = 0000 堆栈的容量为1024字节(400h),并引用堆栈段3996h,这与代码段3995h不同。所以我确信数据不会被混淆 但我不明白的是,当我不得不处理.COM程序

我正在研究.EXE程序和.COM程序之间的区别。 EXE对我来说是合乎逻辑的,堆栈位于与程序代码相关的另一段中(事实上,堆栈是强制的,并用.stack指示此限制),因此,当我转到插入值时​​在堆栈中(在.EXE中),使用与程序不同的段,我不会混淆这两个

例如:

SP = 0400
SS = 3996 CS = 3995 IP = 0000
堆栈的容量为1024字节(400h),并引用堆栈段3996h,这与代码段3995h不同。所以我确信数据不会被混淆

但我不明白的是,当我不得不处理.COM程序时;因为我非常清楚他们只使用一个片段,我发现自己的情况与此类似:

SP = FFEE
SS = 114A CS = 114A IP = 0100

我有与代码段匹配的堆栈段。所以如果我继续坚持价值观​​在堆栈上,它们迟早会出现在我的代码中吗?

虽然MS-DOS在加载COM文件后会将所有段寄存器设置为程序条目上的同一段,但没有什么能阻止您更改寄存器以使用不同的段。然而,您所设想的细分市场之间的硬分离实际上并不存在。即使使用单独的堆栈段,如果堆栈溢出,仍然会写入不应该写入的内存中,并且结果将不可预测

使用CS:IP为114A:0100和SS:SP为114A:FFFE的第二个示例,COM程序可以将SS:SP更改为210A:03FE。这两个SS:SP值都指向相同的线性地址(2149E)和MS-DOS在进入堆栈时推送到堆栈上的相同返回值。现在,堆栈只有1024个字节,就像在in-EXE示例中一样,但堆栈段仍然是64k。在实模式下,分段始终为64k

现在猜猜当SS:SP为210A:0000时,您试图将一个单词推到堆栈上时会发生什么?CPU不会生成异常,它不会以某种方式拒绝执行操作,它只是做它一直在做的事情。它从SP中减去2,然后将该字存储在新的SS:SP地址。在这种情况下,这意味着SP将环绕到FFFE,您推送的值将存储在210A:FFFE或3109E的线性地址

现在的问题是在线性地址3109E分配了什么?MS-DOS可能会将此内存分配给您的程序,并且在其中写入值是无害的,因为您的程序没有将其用于任何用途。但是,有可能某些TSR或驱动程序已经在那里分配了内存,覆盖它将导致崩溃或其他不可预测的行为

如果在堆栈溢出时重写自己的代码实际上会更好,因为这意味着您更有可能注意到错误并修复它。

EXE也存在同样的环绕问题。如果你想要一个真正独立的堆栈,你需要64K的大小,但是溢出时发生的事情是堆栈会覆盖它自己,所以不能从根本上消除这个问题。最终,作为开发人员,您有责任确保您的程序为自己分配了足够的堆栈空间,并且您的代码永远不会超过该限制



请注意,对于COM文件,您需要担心一个与堆栈相关的问题,那就是MS-DOS不能保证能够为您的COM文件分配完整的64K。MS-DOS将为COM文件分配最大的可用内存块。如果该内存块小于64K,则SP不会设置为FFFE,而是将SP设置为指向分配给程序的最后一个字。在最坏的情况下,这意味着堆栈将立即开始覆盖COM文件中的代码和数据。因此,最好在COM文件末尾分配空间,为堆栈保留空间。

a*.COM文件可以使用函数4ah将ram大小调整为可执行文件的最小值,并最终使用函数48h从DOS获得空闲ram。

是,堆栈最终会与您的代码段发生冲突。虽然我只能推测COM格式只支持一个段,但我认为这是(a)因为此模型允许您将8086视为16位机器,忽略所有段寄存器,(b)因为在DOS 1发布时,IBM在任何常规配置中都没有超过64k的内存,而且这么多的内存被认为是非常惊人的。@fuz“所以如果我继续输入值​​当然,考虑到8086段是如何工作的,即使堆栈段与代码段不同(如果它们重叠),也可能发生这种情况。他们通常会这样做,因为谁会需要一个完整的64K的堆栈呢?@Fuz:我相信唯一没有支持的DOS版本是IBM PC-DOS 1.0,它基本上是当时最新的86-DOS的翻版)。86-DOS不支持EXE文件格式(除了后来生产86-DOS的公司最终使用OEM MS-DOS 1.25)。MSDOS版本从1.24开始,支持EXE文件格式。1.24成为IBM PC-DOS1.1的基础(因此IBM PC-DOS1.1+支持EXE)。MS-DOS的编号不是从1.0开始的,因为他们延续了86-DOS的编号方案。CP/M-86也不支持EXE格式。