8086分段内存是一个好主意

Hacker News Top 新闻

摘要

一项回顾性分析认为,8086分段内存架构是一个巧妙的设计,本可以优雅地扩展,但软件开发者坚持将内存视为平坦空间,导致了其被认为存在缺陷。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/06/23 10:42

# 8086分段内存曾是个好主意(差不多是)。—— billpg industries™ 来源:https://owl.billpg.com/8086-segmented-memory-was-a-good-idea-almost/ 这个标题够标题党吧?哪个心智正常的人会为8086那令人发指的分段内存架构辩护? 等我开始学8086汇编的时候,PC已经大多是80286了,但一切仍然在DOS下运行。“正常”的机器只有标准的640KB常规内存,每本汇编书里都有一个让人头疼的章节解释分段。我至今还留着那些“战斗伤疤”:近指针、远指针,还有那个臭名昭著的“你在哪我在哪指针”。 所以,当我自己在设计**Hearthfire(https://owl.billpg.com/hearthfire-part-one-lighting-the-flame/)**——一个假设的1980年代家用电脑项目,借事后之明,且无需承担实际制造硅片的负担——时做出类似架构决策时,我终于理解Intel当初为何那样选择了。分段本来可以成为未来的坚实根基,就差一个小细节,结果全毁了。 而那个细节,尴尬的是,就是我们自己。 软件开发者。 是我们搞砸了。 “有很多话想对你说,但我不知道怎么说。” 8086能够寻址1MB内存,这在当时64KB就算奢侈的时代是个巨大的数量。要做到这一点,需要20位地址。 但Intel没有给程序员提供20位寄存器,而是保留了熟悉的16位寄存器,缺失的4位来自第二组16位寄存器——段寄存器。每次内存访问都结合一个段寄存器和一个16位偏移量。 每个段的起始地址比前一个段多16字节。段之间严重重叠。同一个物理地址可以用多种不同的段+偏移组合来表示。要读取一个字节,你需要加载一个段(起始点)和一个偏移(离该点的距离)。在内部,CPU将段左移4位,然后加上偏移。 两个16位值产生一个20位地址。 难怪人人都恨它。 ## 最后的却成了最先的 嘲笑分段是件时髦事,但在它最初的情境下,这其实相当巧妙。 人们容易把8086看作是x86血统中的“第一”块芯片,尤其是每个后续型号都还带着它的实模式DNA。但故事要从更早讲起。 8080是1970年代中期的中坚力量。它运行着那个时代的主流操作系统CP/M,其16位地址总线给它一个整洁的64KB世界。(Z80是它更出名的表亲。) 随着软件增长,64KB天花板成了问题。客户想要更多内存,但他们也希望现有的汇编代码能继续运行。那时汇编还是人类手写的主要语言,你不能简单地为新CPU重新编译汇编。迁移到新架构真的意味着重写一切。 这样看来,Intel的主意很简单。 “我们把内存分成64KB的段。把你的8080代码加载到其中一个段里,把所有段寄存器指向那里,代码就能像以前一样运行。无需重写。无需折腾。” 从某个角度看,8086看起来像个有先见之明的设计。一个段加一个偏移总共32位,足以寻址4GB。虽然芯片只有20个地址引脚,但下一个芯片可以有更多。扩展段之间的重叠,一切就顺理成章了。 理论上,8086本可以优雅地扩展,直到我们需要64位寻址的那一天。 除了一件事…… ## 最先的却成了最后的 “段”这个名称揭示了Intel的意图。我们本不该把内存看作连续的1MB空间。我们本应该把它看作许多64KB的块,每个块由一个不透明的选择器标识。 你的程序向操作系统请求内存,操作系统给你一个段值。你把它加载到段寄存器中,然后用偏移量在其中索引。需要超过64KB?分配两个块。 但开发者不想要两个块。他们想要一个平坦的地址空间。 一旦人们意识到段之间总是相隔16字节,**规范化指针**就出现了。段寄存器变成了20位地址的高16位;偏移量提供了低4位。稍加处理,你就可以把内存当作几乎是连续的。 到了80286时代,这种做法已经根深蒂固。把重叠从16字节改成256字节会破坏一切。所以Intel为286的高级功能和24位寻址添加了一种新模式,而旧代码则留在实模式。 直到80386及其虚拟8086模式出现,主流软件才终于摆脱了1MB的限制。 如果我们当初都同意把段当作真正的段来对待,8086架构或许能持续数十年。 “那晚,亲爱的,我入睡时,梦见将你拥在怀里。当我醒来,亲爱的,我发现是场梦,于是低头哭泣。” ## 他们本应该怎么做? 这里我得承认,没有简单的解决办法。 事后看来,我们需要的是把段当作真正的选择器——没有任何算术含义的不透明句柄。如果你不能假设下一个段就在前面16字节处,那你就不得不按预期使用分段。 但这需要每个段的元数据、存储这些元数据的空间以及管理它的硬件。而在当时64KB还算很多的时代,这并不现实。 而且即使Intel实现了这样的系统,只需要一个聪明的开发者发现一个未记录的捷径,就能把这种行为变成下一代芯片的硬性要求。 所以Hearthfire不会使用8086风格的分段。但它仍然是一个宝贵的经验教训。 **鸣谢** 📸 “We Picked A Poppy(https://www.flickr.com/photos/nyalr/53454097258/)” by “A Guy Named Nyal”。(Creative Commons) 📸 “I Broke The Build(https://www.flickr.com/photos/dhaun/5626938236/)” by Dirk Haun。(Creative Commons)

相似文章

80386 早期启动内存访问

Hacker News Top

本文解释了 Intel 80386 中的早期启动内存访问技术,该技术通过将地址生成与前一条指令的最后一个周期重叠来隐藏内存延迟。文章描述了该技术在 z386 FPGA 核心中的实现,达到了 ao486 级别的性能,并在 Doom FPS 上提升了 39%。

80386 微码反汇编

Hacker News Top

一篇博客文章,详细介绍了成功反汇编和分析 Intel 80386 微码的过程,揭示了215条指令入口点以及其复杂的内部架构。

将1980年代的内存映射与Raspi Pico进行比较

Hacker News Top

比较1989年摩托罗拉68000内存映射设计与现代树莓派Pico的设计,突出整数地址分配的奢侈性以及内存规模相似性(192KB对比260KB),同时讨论了架构差异和可行性。