Pan*_*der 1 x86 assembly operating-system kernel x86-16
自从我开始使用8086汇编语言编程以来,我一直在思考这些段和段寄存器.我面临的问题是,我无法看到我脑海中存在哪些细分的视觉图像,因此这些概念对我来说并不清楚.
问题1:
据我所知,在启用了20地址线的16位实模式下,我们可以将物理内存分成16段,每段64KiB.第一部分开始于0x00000.下一段的起始地址是什么.是否会添加0x10000(65536 = 64KiB)?
问题2:
这个问题有点奇怪,但仍然是我唯一的选择.假设我给了一个偏移地址0x6000,我怎样才能找到它所属的段以便解决它.
谢谢
...我们可以将物理内存分成16段,每段64KiB.
是的,但更准确的是将其称为"16个非重叠段",因为还有可能将存储器划分为65536个重叠段.
当启用A20线路时,我们可以使用超过1MB的线路.(1048576 + 65536-16)当将相关段寄存器设置为0xFFFF时,我们可以访问0x0FFFF0和0x10FFEF之间的存储器.
两种细分的主要特征是:
重叠的部分
在内存中相隔16个字节.
有时您会看到人们将16字节的内存块称为段,但显然这是错误的.然而,对于如此大量的记忆,有一个广泛使用的名称:" 段落 ".
假设我的偏移地址为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)
在这个答案中,我只是给出了真实模式的解释.在保护模式下,分割有点复杂,因为您可能永远不会编写分段保护模式程序,我不打算解释这一点.
细分实际上非常简单.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但你可以使用任何段选择你喜欢的好.