我正在阅读有关记忆地址的信息。我阅读了有关细分偏移的信息,然后读取了描述符偏移量。我知道如何在实际模式下计算确切的地址。所有这些都可以,但是我无法理解到底是什么偏移?我读到的任何地方:

在实际模式下,寄存器只有16位,因此您最多可以解决64K。为了允许寻址更多内存,地址קד是根据段 * 16 +偏移计算的。

在这里,我可以理解第一行。我们有16位,因此我们最多可以解决2^16 = 64K。

但是第二行是什么?该细分市场代表什么?为什么我们将其乘以16?为什么我们添加偏移。我只是不明白这个偏移是什么?有人可以向我解释或给我链接吗?

有帮助吗?

解决方案

在x86房地机内存下,物理地址长20位,计算出:

PhysicalAddress = Segment * 16 + Offset

还检查: 房地机内存管理

其他提示

当英特尔构建8086时,有一个有效的案例可以在机器中拥有超过64kb的案例,但是它不可能使用32位地址空间。那时,即使是兆字节也是很多记忆。 (还记得臭名昭著的报价“ 640k应该对任何人都足够”?这本质上是对当时1MB怪异的事实的错误翻译 巨大的。)“千兆字节”一词再也不会使用15 - 20年了,在此之后的5 - 10年之后,它不会再用RAM。

因此,他们没有实施如此巨大的地址空间,以至于它“永远不会被充分利用”,而是实施了20位地址。他们仍然使用16位单词进行地址,因为毕竟,这是一个16位处理器。上词是“段”,较低的单词是“偏移”。但是,这两个部分重叠了 - 一个“段”是一个64kb的内存,开始于 (segment) * 16, ,“偏移”可以指向该部分内的任何地方。为了计算实际地址,您将地址的段部分乘以16(或将其左右移动4位...相同的东西),然后添加偏移量。完成后,您有一个20位地址。

 19           4  0
  +--+--+--+--+
  |  segment  |
  +--+--+--+--+--+
     |   offset  |
     +--+--+--+--+

例如,如果该段为0x8000,并且偏移量为0x0100,则实际地址为 ((0x8000 << 4) + 0x0100) == 0x80100.

   8  0  0  0
      0  1  0  0
  ---------------
   8  0  1  0  0

数学很少是整洁的 - 0x80100 可以用实际上数千个不同的片段来表示:偏移组合(如果我的数学正确,4096)。

我想在这里添加一个答案,只是因为我一直在搜寻互联网也试图理解这一点。其他答案是遗漏了我从一个答案中提出的链接中获得的关键信息。但是,我几乎完全错过了它。读取链接页面,我仍然不了解这是如何工作的。

我可能遇到的问题只是真正了解Commodore 64(6502处理器)如何布置记忆。它使用类似的符号来解决内存。它具有64K的总内存,并使用页面的8位值:偏移到访问内存。每个页面为256个字节长(8位编号),偏移点是该页面中值之一。页面在内存中背靠背间隔。因此,第2页从第1页结束。我正在进入386,思考相同的风格。事实并非如此。

实际模式也使用类似的样式,即使它是不同的措辞段:偏移。一个段的大小为64K。但是,这些细分市场本身并未像Commodore那样背靠背布置。它们间隔16个字节。偏移仍然相同,表明页面段启动了多少个字节。

我希望这种解释可以帮助任何发现这个问题的人,它帮助我编写了这个问题。

我可以看到问题和答案已有数年历史,但是有一个错误的陈述,即实际模式中只有16位寄存器。

在实际模式下,寄存器不仅是16位,因为也有8位寄存器。这8位寄存器中的每一个都是16位寄存器的一部分,该寄存器分为16位寄存器的较低和较高部分。

并从80386+开始实现真实模式,我们成为32位寄存器,另外还有两个新的指令前缀,一个是覆盖/反向默认操作数大小,另一个是覆盖/反向一个指令的默认地址内部的默认地址,一个编号。

这些说明前缀可以组合使用,以扭转操作数大小和地址大小以进行一项指令。在实际模式下,默认操作数大小和地址大小为16位。使用这两个指令前缀,我们可以使用32位操作数/寄存器示例来计算一个32位寄存器中的32位值,或者从memmory位置移动32位值。我们可以将所有32位寄存器(可能与基本+索引*比例+位移结合使用)作为地址注册,但是有效地址的总和不必超过64 kb段的限制。

(在Osdev Wiki页面上,我们可以在表中找到“操作数大小和地址大小的替代前缀”,即“ 0x66操作派前缀”和“ 0x67地址前缀”是n/a(不可用)真实模式和虚拟8086模式。 http://wiki.osdev.org/x86-64_instruction_encoding
但这完全是错误的,因为在英特尔手册中,我们可以找到此说法:“这些前缀可以在实地地址模式以及受保护模式和虚拟-8086模式下使用”。)。

从奔腾MMX开始,我们成为八个64位MMX-Registers。
从奔腾3开始,我们成为八个128位XMM登记仪。
..

如果我没有错,那么256位ymm register和512位zmm register和x64的64位通用寄存器无法在实际模式中使用。

短剑

最小例子

和:

  • 偏移= msg
  • 细分= ds
mov $0, %ax
mov %ax, %ds
mov %ds:msg, %al
/* %al contains 1 */

mov $1, %ax
mov %ax, %ds
mov %ds:msg, %al
/* %al contains 2: 1 * 16 bytes forward. */

msg:
.byte 1
.fill 15
.byte 2

因此,如果要访问64K以上的内存:

mov $0xF000, %ax
mov %ax, %ds

请注意,如果您使用类似的内容,则可以使用大于20位的地址:

0x10 * 0xFFFF + 0xFFFF == 0x10FFEF

在仅有20条地址线的较早处理器上,它只是被截断了,但后来在A20线(第21台地址线)的情况下变得复杂了: https://en.wikipedia.org/wiki/a20_line

Github仓库 使用所需的样板运行它。

16位寄存器只能地址为0xFFFF(65,536字节,64KB)。如果这还不够,英特尔添加了细分寄存器。

任何逻辑设计都会简单地将两个16位寄存器组合在一起,以制作32位地址空间(例如 0xFFFF : 0xFFFF = 0xFFFFFFFF), 但 ...英特尔必须使我们一切怪异。

从历史上看,前后巴士(FSB)只有20条地址线,因此只能传输20位地址。到 “纠正” 这是Intel设计的一个方案,其中细分市场仅将您的地址扩展到4位(理论上,16位 + 4 = 20)。

为此,该片段寄存器从其原始值左移4位,然后添加到您的常规寄存器中的地址 (例如 [es:ax] = ( es << 4 ) + ax). 注意:左移动4位等效于乘以16.

就是这样。这里有一些说明性的例子:

;; everything's hexadecimal

[ 0:1 ] = 1

[ F:1 ] = F1

[ F:0 ] = F0

[ F:FF] = 1EF ; [F becomes F0, + FF = 1EF]

[ F000 : FFFF ] = FFFFF (max 20-bit number)

[ FFFF : FFFF ] = 10FFEF (oh shit, 21-bit number!)

因此,您仍然可以解决20位以上。发生什么了?地址“环绕”,例如模量算术(作为硬件的自然结果)。所以, 0x10FFEF 变成 0xFFEF.

那里有!英特尔聘请了一些愚蠢的工程师,我们必须忍受它。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top