Assembly 如何使用分段来扩展内存?

Assembly 如何使用分段来扩展内存?,assembly,memory,x86,Assembly,Memory,X86,我试图理解记忆模型,特别是分段的和扁平的。然而,大多数参考资料都太过技术化,似乎分段可以用来“扩展”内存,但这意味着什么?它是如何实现的? 另外,在使用分段内存模型时,为什么一次只能使用64KB的地址 为什么一次只能使用64KB的地址 因为这就是16位偏移量在一个段中可以寻址的量 实模式下的x86分段只是线性地址=segreg 为什么一次只能使用64KB的地址 因为这就是16位偏移量在一个段中可以寻址的量 实模式下的x86分段只是linear address=segreg64 KiB限制不是使用

我试图理解记忆模型,特别是分段的和扁平的。然而,大多数参考资料都太过技术化,似乎分段可以用来“扩展”内存,但这意味着什么?它是如何实现的? 另外,在使用分段内存模型时,为什么一次只能使用64KB的地址

为什么一次只能使用64KB的地址

因为这就是16位偏移量在一个段中可以寻址的量

实模式下的x86分段只是
线性地址=segreg
为什么一次只能使用64KB的地址

因为这就是16位偏移量在一个段中可以寻址的量


实模式下的x86分段只是
linear address=segreg64 KiB限制不是使用分段时固有的,而是x86分段诞生和使用最多的环境,即16位x86处理器,其中地址为16位宽,因此只能索引64 KiB内存。1

分段本质上是一个绕过此限制的技巧:每个分段(大致)包含一个基址,您可以隐式或显式地引用一个16位地址。这允许您在较大的物理地址空间(稍后为虚拟地址空间)内同时拥有5个64 KiB的“视图”;这些视图也可以通过在相关段寄存器中加载不同的地址来移动

这个技巧特别有效,不同的指令在默认情况下使用不同的指令(通常用于大部分隔离的数据)默认情况下引用不同的段

代码是从CS(代码段)读取的,因此16位指令指针和近调用将引用它。堆栈指令(
push
pop
call
ret
)在堆栈段上运行;SP和BP通常相对于SS(堆栈段)进行解释

默认情况下,可以在内存操作数上操作的所有其他指令都在DS(数据段)上工作,除非您使用SP或BP作为基址寄存器,因为这意味着您在堆栈上操作,因此假定为SS;不过,您可以添加一个前缀,允许对另一段进行操作

最后,字符串指令对读时DS(可重写)和写时ES进行操作。这允许在数据空间(或另一段)和64 KiB以外的另一个位置之间轻松高效地复制数据。一种典型的安排是将ES指向视频存储器,并使用字符串指令在屏幕上复制图像数据

因此,一般来说,即使不改变段,您也可以通过ES(自80386年以来添加了FS和GS的三个)获得不同的64 KiB堆栈、代码、数据和一个“附件”地址空间,因此您可以同时寻址高达2 256 KiB(384 KiB)的内存,同时仍然保持(大部分)周围只有16位指针-尽管您必须记住它们所指的段

现在,一旦您需要实际寻址更多内存,那么事情就变得更加困难,从而在程序运行时更改段寄存器

代码非常简单-如果需要调用当前CS之外区域中的函数,则需要通过32位远指针执行“远调用”;只要远调用和远返回是匹配的,并且没有人尝试对代码进行近调用,这实际上是远调用,那么一切都会顺利进行

数据更加微妙;输入远指针、近指针,各种奇怪的DOS内存模型和东西很快就会变得杂乱无章——当用C这样的高级语言编程时,你不得不担心这种超低级的细节。我没有在内存模型中编写有远指针的软件的第一手经验,所以我不能分享我自己的经验,但是每个谈论它的人都同意它一点也不漂亮,我们都很高兴来到这样一个世界:指针只是一个平面地址空间中的指针


笔记
  • 即使在32位平面寻址模式下,您仍然使用段寄存器,但它们都设置为零,因此所有段都相同,并且在您使用的地址和实际访问的内存之间不执行转换。FS/GS是一个例外,因为现代操作系统通常使用FS/GS来引用包含线程上下文数据的内存块
  • 请记住,段可能会重叠。顺便说一句,这在高级语言中导致了进一步的复杂化,因为远指针的数字比较并没有给出实际指向地址相等的信息

  • 64 KiB限制不是使用段时固有的,而是x86段诞生和使用最多的环境,即16位x86处理器,其地址为16位宽,因此只能索引64 KiB内存。1

    分段本质上是一个绕过此限制的技巧:每个分段(大致)包含一个基址,您可以隐式或显式地引用一个16位地址。这允许您在较大的物理地址空间(稍后为虚拟地址空间)内同时拥有5个64 KiB的“视图”;这些视图也可以通过在相关段寄存器中加载不同的地址来移动

    这个技巧特别有效,不同的指令在默认情况下使用不同的指令(通常用于大部分隔离的数据)默认情况下引用不同的段

    代码是从CS(代码段)读取的,因此16位指令指针和近调用将引用它。堆栈指令(
    push
    pop
    call
    ret
    )在堆栈段上运行;SP和BP通常相对于SS(堆栈段)进行解释

    默认情况下,可以在内存操作数上操作的其他每一条指令都可以工作