Assembly 什么是段,如何在8086模式下寻址?

Assembly 什么是段,如何在8086模式下寻址?,assembly,x86,operating-system,kernel,x86-16,Assembly,X86,Operating System,Kernel,X86 16,自从我开始使用8086汇编语言编程以来,我一直在反复思考这些段和段寄存器。我面临的问题是,我无法直观地了解我头脑中的各个部分,因此我不清楚这些概念 有人能帮我理解将其与现实世界场景联系起来的概念吗?我还有以下问题: 问题1: 据我所知,在启用20地址线的16位实模式下,我们可以将物理内存划分为16个段,每个段64KiB。第一段从0x00000开始。下一段的起始地址是什么。是否通过添加0x10000(65536=64KiB)来实现 问题2: 这个问题在这里问起来有点奇怪,但这仍然是我唯一的选

自从我开始使用8086汇编语言编程以来,我一直在反复思考这些段和段寄存器。我面临的问题是,我无法直观地了解我头脑中的各个部分,因此我不清楚这些概念


  • 有人能帮我理解将其与现实世界场景联系起来的概念吗?我还有以下问题:
问题1:

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

问题2:

这个问题在这里问起来有点奇怪,但这仍然是我唯一的选择。假设我的偏移地址为
0x6000
,我如何找到它所属的段来对其进行寻址


谢谢

在这个回答中,我只是对真实模式进行了解释。在保护模式下,分段比较复杂,因为您可能永远不会编写分段保护模式程序,所以我不打算对此进行解释


片段实际上非常简单。8086 CPU有四个段寄存器,分别名为
cs
ds
es
ss
。当您访问内存时,CPU计算物理地址,如下所示:

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

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

正如您在上面的地址计算逻辑中所看到的,这些段中的每一段都从16的倍数开始。您可以将整个1 MiB物理地址空间平铺为16个不重叠的段(正如您在问题中所解释的那样)值
0x0000
0x1000
,…,
0xf000
,但也可以使用您喜欢的任何段选择器

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

没错,但更准确的说法是“16个不重叠的段”,因为也有可能将内存划分为65536个重叠的

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

这两种细分市场的主要特点是:

  • 非重叠段
    • 包含65536字节
    • 内存中相隔65536字节
    • 这就是我们这些人看待记忆的方式。它使我们能够说我们已经
      • A段中的图形窗口(0xA0000-0xAFFF)
      • B段中的文本视频窗口(0xB0000-0xBFFFF)
      • F段中的BIOS(0xF0000-0xFFFFF)
  • 重叠段

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

      有时你会看到人们把一个16字节的内存块称为一个段,但显然这是错误的。然而,对于这样的内存量,有一个广泛使用的名称:“段落”

    • 这是CPU(在实地址模式下)查看内存的方式。
      处理器使用以下步骤计算线性地址:
      • 首先计算指令操作数的偏移地址。结果被截断以适合16位(64KB环绕)
      • 接下来添加分段寄存器*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
    
    正如您所看到的,有0x0601可能的段寄存器设置,可以访问线性地址0x6000。
    上述规定适用于A20线路确实启用的情况。如果A20处于非活动状态,则可以通过精确的0x1000(4096)方式访问线性地址0x6000(就像从0到1MB-1的任何其他线性地址一样):


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

    如果将内存看作一个长字节数组
    mem[0x100000]
    ,则可以指定一个con
    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