assembly x86真实的模式下的段大小

vsikbqxv  于 2022-12-13  发布在  其他
关注(0)|答案(2)|浏览(162)

我对真实的模式下的段大小有一点怀疑,因为它们不能超过64K,但可以是less than that.
我的问题是这些段的大小和基址是如何初始化的?就像保护模式下的GDT和LDT一样。Real mode segments can also overlapped,disjoint or adjacent.
像BIOS有一些保留区域的具体事情,如 Boot 代码,视频缓冲区等汇编程序需要这样做吗?

gmxoilav

gmxoilav1#

真实的模式下的段限制为64 K,即使在386或更高版本的CPU上,您也可以通过前缀使用32位地址大小。例如,mov ax, [edx + ecx*4]在实模式下的偏移量仍限制为64 KiB。

如果超出此限制,则会在286+上引发#GP异常(如果段为SS,则为#SS)。
8086没有#SS或#GP异常,它没有一般或其他保护,只是使用Sreg << 4添加到偏移量以形成线性地址。
16-位地址大小可以通过seg:FFFF上的一个字或更宽的访问超过64 K段限制。在8086上,较高的字节来自seg:0000(在计算第二个内存总线事务的新线性地址之前,在逻辑地址中的偏移回绕,而不是访问段的64 K线性范围之外)。
在286和更高版本上,在这种情况下,数据和指令都为#GP#SS。* https://www.os2museum.com/wp/does-eip-wrap-around-in-16-bit-segments/ *
一般而言,像[bx + si + 1]这样的寻址模式在16位处换行。(而SP=0的push word会自动换行到SP=FFFEh,只要堆栈对齐就没有问题)。(在386中添加的)可以超过真实的模式中的段限制,除了在段的最末端的字或更宽的访问。
在8086上,从最高可能地址的64 K以内开始的段在1 MiB处环绕,如果禁用A20,则在更高的CPU上也是如此。否则,对于FFFF:FFFF seg:off = 0x10ffef linear这样的地址,它们会延伸到1 MiB以上。请参阅 * 什么是段以及如何在8086模式下对其进行寻址?*

虚幻模式:386真实的模式平面存储器模型

如果您切换到保护模式并设置了段寄存器,CPU会将段描述(基址+限制)保留在内部缓存中,即使切换回16位真实的模式也是如此。这种情况称为**unreal mode**。

在16位模式下写入段寄存器只会将段基址设置为value << 4,而不会改变限制,因此非真实模式对于除CS之外的段是比较持久的。CS:EIP是特殊的,特别是当你需要避免在从中断返回时将EIP截断为16位时。
push/pop/call/ret根据当前堆栈段描述符中得B标志使用SS:ESPSS:SP;地址大小前缀仅影响类似于push word [eax]push word [si]的内容。

在真实的模式下向段寄存器写入值时,GDT / LDT被忽略。该值直接用于设置缓存的段基址,而根本不作为选择器。

(Each分段;虚幻模式不是像protected与real那样的实际模式; CPU处于真实的模式。例如,写FS寄存器会将该段恢复到正常的实模式行为,但不会改变其他行为。它只是一个名称,表示处于实模式,缓存的段描述符具有更大的限制,因此您可以使用32位地址大小来获得更大的平面地址空间。通常base=0,limit=4G)
当然,在真实的模式下无法查询段的内部限制值。lsl直接从内存中GDT / LDT的描述符中加载段限制值,而不是从内部值中加载(因此这不是您想要的),而且它在实模式下也不可用。
有关有意或无意地使片段脱离虚幻模式的更多详细信息,请参见对此答案的注解。
286和386 CPU支持a LOADALL instructiona LOADALL instruction可以从真实的模式设置段限制,但后来的CPU没有它。评论者说SMM(系统管理模式)可能能够在现代x86上做类似的事情。

rryofs0p

rryofs0p2#

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

physical address = segment * 16 + offset

段地址和偏移地址都是16位的。通过使用这个等式,你可以制作一个20位的地址,访问低640kB的RAM没有问题。
没有一个表来保存某个段的位置。问题是你必须同时设置段寄存器和偏移寄存器才能访问任何地址。所以你可以通过一个简单的循环访问最多64k的RAM字节,这个循环只是增加偏移寄存器,这使得内存访问更大的缓冲区比在平面模型中更不方便。

相关问题