Assembly 什么是段,如何在8086模式下寻址?
自从我开始使用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: 这个问题在这里问起来有点奇怪,但这仍然是我唯一的选
- 有人能帮我理解将其与现实世界场景联系起来的概念吗?我还有以下问题:
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