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

时间:2017-03-17 15:31:50

标签: assembly x86 operating-system kernel x86-16

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

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

问题1:

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

问题2:

这个问题在这里有点奇怪,但仍然是我唯一的选择。假设我的偏移地址为0x6000,我如何找到它所属的段以便解决它。

谢谢

3 个答案:

答案 0 :(得分:6)

  

...我们可以将物理内存分成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环绕。
  3.   

    假设我的偏移地址为0x6000,我怎样才能找到它所属的段以便解决它。

    这里的问题还在于措辞!

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

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

    segment:offset
    --------------
       0000:6000
       0001:5FF0
       0002:5FE0
       0003:5FD0
       ...
       05FD:0030
       05FE:0020
       05FF:0010
       0600:0000
    

    正如您所看到的,可能有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
    

答案 1 :(得分:5)

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

实际上细分非常简单。 8086 CPU有四个段寄存器,名为csdsesss。当您访问内存时,CPU会像这样计算物理地址:

physical_address = segment * 16 + effective_address

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

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

这些段中的每一个都从一个16的倍数开始,如上面的地址计算逻辑所示。您可以使用16个非重叠片段(如您在问题中所述)标注整个1 MiB物理地址空间值0x00000x1000,...,0xf000但您可以使用您喜欢的任何细分选择器。

答案 2 :(得分:2)

通常,段是使用内部索引系统的内存间隔。

如果您将内存视为一长串字节mem[0x100000],您可以指定连续切片seg=mem[a:a+b],其中len(seg)=b其中

  • seg[0]存储在mem[a]
  • seg[1]存储在mem[a+1]
  • ...
  • seg[b-1]存储在mem[a+b-1]

使用分段的优点是,分段内的地址(seg的索引)可以更短,例如,在8086的情况下,可寻址存储器上升到物理地址(mem的索引)2 20 -1,(在后继上你甚至可以更进一步,在段中有16位地址) 。 将程序放在内存中的任何位置都相当简单,因为您只需要分配一个或几个空闲段,并且大多数地址在专用段内运行而无需调整它们。

在8086上,所有段都是2 16 字节长,因此段内地址适合16位,这使得它们易于处理。对于起始地址,您可以选择物理内存中可以除以16且等于或低于0xFFFF0的任何地址。这意味着任何物理地址都位于多个段中。这些段由16位数字描述,它是起始地址除以16。

因此,细分0xBADA对应于从0xBADA0开始的细分。