x86实模式下的段大小

x86实模式下的段大小,x86,memory-segmentation,real-mode,X86,Memory Segmentation,Real Mode,我对实模式下的段大小有一个疑问,因为它们不能超过64K,但我的问题是这些段大小和基址是如何初始化的?像GDT和LDT在保护模式下一样。像BIOS有一些保留区域用于特定的事情,如引导代码、视频缓冲区等。汇编程序需要这样做吗?在实模式下,分段地址硬连线到内存中。要获得物理地址,可以使用以下等式: physical address = segment * 16 + offset 段地址和偏移地址均为16位。通过使用这个等式,您可以创建一个20位地址,并且可以毫无问题地访问低640kB的RAM 在某些

我对实模式下的段大小有一个疑问,因为它们不能超过64K,但我的问题是这些段大小和基址是如何初始化的?像GDT和LDT在保护模式下一样。像BIOS有一些保留区域用于特定的事情,如引导代码、视频缓冲区等。汇编程序需要这样做吗?

在实模式下,分段地址硬连线到内存中。要获得物理地址,可以使用以下等式:

physical address = segment * 16 + offset
段地址和偏移地址均为16位。通过使用这个等式,您可以创建一个20位地址,并且可以毫无问题地访问低640kB的RAM

在某些段所在的位置没有表。
问题是您必须同时设置段寄存器和偏移寄存器才能访问任何地址。因此,您可以通过一个简单的循环来访问最多64k的RAM字节,该循环仅增加偏移寄存器,这使得对较大缓冲区的内存访问不如在平面模式下舒适。

实模式下的段限制为64k,即使在386或更高版本的CPU上,您可以通过前缀使用32位地址大小。e、 g.
mov-ax,[edx+ecx*4]
在实模式下仍被限制为64千磅的偏移量

如果超过此限制,将引发#GP异常。(或
#SS
如果段为SS)


16位地址大小不能超过64k段限制,因为像
[bx+si]
这样的寻址模式以16位换行。因此,只有在实模式下使用
0x67
地址大小前缀(在386中添加)的代码才能运行到段限制。8086不必检查限制,只需添加
Sreg谢谢nio的回答。那么决定段的基址和段的大小是汇编程序员的工作吗?如果是这种情况,段可以重叠,而重叠的另一段可以被其他程序使用,从而损坏数据?假设两个MSDOS程序正在运行,在没有保护的情况下如何分配内存?我不确定DOS中的内存管理是如何工作的,但这里有一些内存地址表:如果你正在编写一个DOS程序,你必须小心不要覆盖其他.com驱动程序或TSR例程。通常一次只运行一个DOS程序。@nio:如果将对象安排为段落对齐,则只需加载段寄存器即可访问存储在对象内已知偏移量处的内容。我不知道有哪种编译语言能利用这一点,但这是汇编代码中的常见技巧不完全正确。如果您处于“非真实模式”,并且您修改了段寄存器,描述符缓存基数将相应地改变,但描述符缓存限制将被忽略。在下次切换到保护模式并更改相关段寄存器的段限制和基址之前,非真实模式应保持不变。在真实模式(包括非真实)下,有另一种机制可以更改它们,即通过LOADALL指令,但该指令在大多数处理器上不可用。LOADALL指令在Intel 386和286s上非常有用,因为您可以在不切换到保护模式的情况下有效地获得非真实模式。Ona 286这是一个额外的功能,因为从保护模式切换回真实模式会带来高性能成本。并且,作为记录,在80年代末90年代初,当某些BIOS中断被使用时(驱动器访问等),有一些不寻常的BIOS悄悄地切换到保护模式(可能会重置非真实模式)。@HadiBrais:可能不止这些。在386年代早期调用
Int 6h
(无效操作码)(使用某些BIOSS)是为了在没有全功能286 LOADALL指令的情况下模拟LOADALL。这后来在一些系统上通过SMM进行了模拟。@HadiBrais关于SMM和Int 6h,需要了解RSM。它的执行状态类似于LOADALL,SMM可以在返回到以前的CPU模式之前修改状态,其效果是模拟大部分LOADALL,而int 6h不会更改为保护模式(以设置非真实模式):