什么是细分以及如何在8086模式下解决这些问题?

Pan*_*der 1 x86 assembly operating-system kernel x86-16

自从我开始使用8086汇编语言编程以来,我一直在思考这些段和段寄存器.我面临的问题是,我无法看到我脑海中存在哪些细分的视觉图像,因此这些概念对我来说并不清楚.


  • 任何人都可以帮助我理解将其与现实世界场景相关联的概念吗?我还有以下问题:

问题1:

据我所知,在启用了20地址线的16位实模式下,我们可以将物理内存分成16段,每段64KiB.第一部分开始于0x00000.下一段的起始地址是什么.是否会添加0x10000(65536 = 64KiB)?

问题2:

这个问题有点奇怪,但仍然是我唯一的选择.假设我给了一个偏移地址0x6000,我怎样才能找到它所属的段以便解决它.

谢谢

Fif*_*nik 7

...我们可以将物理内存分成16段,每段64KiB.

是的,但更准确的是将其称为"16个非重叠段",因为还有可能将存储器划分为65536个重叠段.

当启用A20线路时,我们可以使用超过1MB的线路.(1048576 + 65536-16)当将相关段寄存器设置为0xFFFF时,我们可以访问0x0FFFF0和0x10FFEF之间的存储器.

两种细分的主要特征是:

  1. 不重叠的细分
    • 包含65536个字节.
    • 在内存中相隔65536个字节.
    • 这是我们人们经常方便地查看记忆的方式.它使我们能够说我们已经放了
      • A段中的图形窗口(0xA0000-0xAFFFF)
      • B段中的文本视频窗口(0xB0000-0xBFFFF)
      • F段中的BIOS(0xF0000-0xFFFFF)
  2. 重叠的部分

    • 包含65536个字节.
    • 在内存中相隔16个字节.

      有时您会看到人们将16字节的内存块称为段,但显然这是错误的.然而,对于如此大量的记忆,有一个广泛使用的名称:" 段落 ".

    • 这是CPU(在实地址模式下)看到内存的方式.
      处理器使用后续步骤计算线性地址:
      • 首先从指令的操作数计算偏移地址.结果被截断以适合16位(64KB环绕).
      • 接下来添加了SegmentRegister的产品*16
        如果A20线路处于非活动状态,则结果将被截断以适合20位(1MB环绕).
        如果A20线路处于活动状态,则结果将按原样使用,因此不会发生1MB环绕.

假设我的偏移地址为0x6000,我如何找到它所属的段以便解决它.

这里的问题还在于措辞!

如果通过"偏移地址0x6000"表示偏移量,就像我们通常在实际地址模式编程中使用的那样,那么问题就无法回答,因为在每个存在的段中都存在这样的偏移量0x6000!

另一方面,如果"偏移地址0x6000"的措辞实际上是指线性地址 0x6000,那么段寄存器有很多解决方案:

segment:offset
--------------
   0000:6000
   0001:5FF0
   0002:5FE0
   0003:5FD0
   ...
   05FD:0030
   05FE:0020
   05FF:0010
   0600:0000
Run Code Online (Sandbox Code Playgroud)

如您所见,存在0x0601可能的段寄存器设置,以获得线性地址0x6000.
以上适用于确实启用A20线路的情况.如果A20处于非活动状态,则可以精确地以0x1000(4096)方式达到线性地址0x6000(就像从0到1MB-1的任何其他线性地址一样):

segment:offset
--------------
   F601:FFF0
   F602:FFE0
   F603:FFD0
   ...
   FFFD:6030
   FFFE:6020
   FFFF:6010
   0000:6000
   0001:5FF0
   0002:5FE0
   0003:5FD0
   ...
   05FD:0030
   05FE:0020
   05FF:0010
   0600:0000
Run Code Online (Sandbox Code Playgroud)


fuz*_*fuz 6

在这个答案中,我只是给出了真实模式的解释.在保护模式下,分割有点复杂,因为您可能永远不会编写分段保护模式程序,我不打算解释这一点.


细分实际上非常简单.8086 CPU有四个段寄存器命名cs,ds,es,和ss.当您访问内存时,CPU会像这样计算物理地址:

physical_address = segment * 16 + effective_address
Run Code Online (Sandbox Code Playgroud)

其中effective_address是内存操作数指示的地址,segment是该内存访问的段寄存器的内容.默认情况下,cs在CPU获取代码时ss使用,用于堆栈推送和弹出以及作为bp基址寄存器的存储器操作数,es用于某些特殊指令并ds在其他任何地方使用.可以使用段前缀覆盖段寄存器.

这在实践中意味着什么?8086有16位寄存器,因此使用寄存器存储地址允许我们寻址高达65536字节的RAM.使用段寄存器的想法是我们可以在段中存储地址的附加位,允许程序员寻址超过2 20 = 1048576字节= 1 MiB的RAM.该RAM被分成65536个重叠段,每段65536字节,其中每个段是一个可以加载到段寄存器中的值.

正如您在上面的地址计算逻辑中所看到的,这些段中的每一个都从一个16的倍数开始.你可以用瓷砖16个非重叠段整个1 MIB物理地址空间中的值(如你在你的问题中详细说明)0x0000,0x1000......,0xf000但你可以使用任何段选择你喜欢的好.