实模式下的段限制为 64k,即使在 386 或更高版本的 CPU 上,您也可以通过前缀使用 32 位地址大小。例如mov ax, [edx + ecx*4] 在实模式下仍然限制为 64 kiB 的偏移量。
如果超出此限制,则会引发#GP 异常。 (或者 #SS 如果段是 SS)。
16 位地址大小不能超过 64k 段限制,因为像 [bx + si] 这样的寻址模式以 16 位包装。因此,只有在实模式下使用0x67 地址大小前缀(在 386 中添加)的代码才会遇到段限制。 8086 不必检查限制,只需将Sreg << 4 添加到寻址模式的偏移量,使限制隐式为 64k。
在最高可能地址的 64k 内开始的段在 8086 上以 1MiB 环绕,如果 A20 被禁用,则在更高版本的 CPU 上环绕。否则,对于FFFF:FFFF seg:off = 0x10ffef 线性这样的地址,它们会超过 1MiB。见What are Segments and how can they be addressed in 8086 mode?
如果切换到保护模式并设置段寄存器,CPU 会在内部缓存段描述(基址 + 限制),即使切换回 16 位实模式也是如此。这种情况称为unreal mode。
在 16 位模式下写入段寄存器只会将段基址设置为 value << 4 而不会更改限制,因此 unreal 模式对于 CS 以外的段来说有些持久。 CS:EIP 是特殊的,特别是如果您需要避免在从中断或其他情况返回时将 EIP 截断为 16 位。请参阅该 osdev wiki 链接。
push/pop/call/ret 根据当前堆栈段描述符中的B 标志使用SS:ESP 或SS:SP;地址大小前缀仅影响 push word [eax] 与 push word [si] 之类的内容。
在实模式下将值写入段寄存器时会忽略 GDT / LDT。该值直接用于设置缓存段基数,根本不作为选择器。
(每个段都是独立的;虚幻模式不是像受保护与真实那样的实际模式;CPU 处于实模式。例如,写入 FS 寄存器会使该段恢复正常的实模式行为,但是不会改变其他。它只是在实模式下使用具有更大限制的缓存段描述符的名称,因此您可以将 32 位地址大小用于更大的平面地址空间。通常使用 base=0 和 limit=4G )
AFAIK,在实模式下无法查询段的内部限制值。 lsl 直接从内存中 GDT / LDT 中的描述符加载段限制值,而不是从内部值(所以这不是您想要的),并且无论如何它在实模式下都不可用。
有关有意或无意将片段脱离虚幻模式的更多详细信息,请参阅此答案上的 cmets。
286 和 386 CPU 支持 a LOADALL instruction,这可以从实模式设置段限制,但后来的 CPU 没有它。评论者说,SMM(系统管理模式)或许能够在现代 x86 上做类似的事情。