为什么x86丑陋?与其他人相比为什么被认为是次等的?[关闭]


105

最近,我一直在阅读一些SO档案,并遇到了针对x86体系结构的声明。

还有更多评论,例如

我尝试搜索,但没有找到任何原因。我认为x86不错,可能是因为这是我所熟悉的唯一体系结构。

有人可以给我理由比其他人考虑x86丑/坏/劣等。


1
我将根据到目前为止的答案来进行S&A,但我会顺便指出,CISC对于m68k指令集不是问题。x86就是它,您可以保留它。
dmckee ---前主持人小猫,2010年

什么是“ S&A”?“对于m68k指令集,CISC并不是问题。” - 为什么不?
爪子

5
摩托罗拉68000系列芯片具有高度的CISC架构,但它们具有统一,相当正交且非常简单的指令集。为什么与x86不同?我不知道。但是请注意,芯片的复杂性与指令集(即,汇编程序员所看到的接口中)的复杂性之间存在很大差异。
dmckee ---前主持人小猫,2010年

4
+1是一个非常有趣的问题。
图灵完成了2010年

1
最近在这里对不同处理器的能效进行了研究,并对推动CISC和RISC设计的因素进行了很好的讨论。extremetech.com/extreme/...

Answers:


93

可能的几个原因:

  1. x86是一个相对较旧的ISA(毕竟它的祖先是8086s)
  2. x86已经发展了好几次,但是需要硬件来保持与旧二进制文件的向后兼容性。例如,现代的x86硬件仍然支持本地运行16位代码。此外,还存在几种内存寻址模型,以允许较早的代码在同一处理器上进行互操作,例如实模式,保护模式,虚拟8086模式和(amd64)长模式。这会使某些人感到困惑。
  3. x86是CISC机器。长期以来,这意味着它比MIPS或ARM等RISC机器要慢,因为指令具有数据依赖性和标志,使得大多数形式的指令级并行性难以实现。现代实现将x86指令转换为类似RISC的指令,称为“ 微操作 ”,以使这些优化在硬件中切实可行地实现。
  4. 在某些方面,x86并不逊色,只是有所不同。例如,输入/输出在绝大多数体系结构上都作为内存映射来处理,而在x86上则不是。(注意:现代的x86机器通常具有某种形式的DMA支持,并通过内存映射与其他硬件进行通信;但是ISA仍具有I和O指令,如INOUT
  5. x86 ISA具有很少的体系结构寄存器,这可以迫使程序比其他情况更频繁地往返于内存。尽管执行有效的存储转发,但执行此操作所需的额外指令会占用执行资源,这些资源可能会用于有用的工作保持较低的延迟。将寄存器重命名为大型物理寄存器文件的现代实现可以使许多指令保持运行状态,但是缺少体系结构寄存器仍然是32位x86的显着弱点。x86-64的整数从8增加到16,向量寄存器是64位代码快于32位(以及更高效的寄存器调用ABI)的最大因素之一,而不是每个寄存器的宽度增加。从16个整数寄存器进一步增加到32个整数寄存器将有所帮助,但效果不尽如人意。(但是,由于浮点代码具有更高的延迟并且通常需要更多的常量,因此AVX512确实增加了32个向量寄存器。)(请参阅注释
  6. x86汇编代码很复杂,因为x86是具有许多功能的复杂体系结构。一台典型的MIPS机器的说明清单可以放在单个字母大小的纸上。x86的等价清单包含多个页面,而说明仅提供更多功能,因此与清单所提供的相比,您通常需要对它们的作用进行更大的解释。例如,MOVSB指令需要相对较大的C代码块来描述其功能:

    if (DF==0) 
      *(byte*)DI++ = *(byte*)SI++; 
    else 
      *(byte*)DI-- = *(byte*)SI--;
    

    那是一条指令来执行加载,存储和两个加法或减法(由标志输入控制),每个指令在RISC机器上都是单独的指令。

    虽然MIPS(和类似的体系结构)的简单性并不一定会使它们更胜一筹,但对于讲解汇编程序类的入门知识而言,从更简单的ISA开始是有意义的。一些汇编类讲授x86的超简化子集y86,将其简化为对实际使用无用(例如,没有移位指令),或者讲授一些基本的x86指令。

  7. x86使用变长操作码,这会增加指令解析方面的硬件复杂性。在现代时代,由于CPU受内存带宽的限制越来越多,而不是受原始计算的限制,因此这种成本正变得越来越小,但是许多“ x86扑朔迷离”的文章和态度来自这种成本相对更大的时代。
    2016年更新:Anandtech发布了有关x64和AArch64下操作码大小讨论

编辑:这不应该是x86的重击!派对。考虑到问题的措辞方式,我别无选择,只能做一些抨击。但是,除了(1)以外,所有这些操作都是有充分理由的(请参见注释)。英特尔设计师并不愚蠢-他们想通过自己的体系结构来实现某些目标,而这些正是为使这些目标变为现实而必须支付的一些税款。


17
这是一个权衡。优点是二进制大小可能会更小,但缺点是您需要非常复杂的硬件才能为这些指令实现解析器。无论如何,绝大多数指令的大小都是相同的-在x86上使用可变长度操作码的主要原因是,当他们决定添加功能并发现它们无法代表所需的位数时, 。绝大多数人对二进制大小的关注几乎不如硬件复杂度或功耗那么大。
Billy ONeal

8
@Joey Adams:将x86的可变长度指令与ARM的Thumb模式(en.wikipedia.org/wiki/ARM_architecture#Thumb)进行对比。拇指模式可以大大减少ARM的目标代码,因为较短的指令直接映射到普通指令。但是,由于较大的指令与较小的指令之间存在1:1的映射关系,因此解析硬件易于实现。x86的可变长度指令没有这些好处,因为它们并不是一开始就设计成这种方式。
Billy ONeal 2010年

7
(6)并不是每个程序都需要使用每个操作码,但是该死的,当我需要SSE3时,我很高兴拥有它。
克里斯K 2010年

4
@Chris Kaminski:那怎么不影响硬件?当然,在现代的全尺寸计算机上,没人会在意,但是如果我要生产手机之类的产品,那么我将比其他任何事情都更关心功耗。可变长度的操作码不会增加执行时间,但是解码硬件仍然需要电源才能运行。
Billy ONeal

5
这是使x86指令集如此丑陋的原因之一,因为它无法确定它是基于累加器还是基于寄存器文件的体系结构(尽管大多数情况下386已解决此问题,这使指令集更加正交,无论68k粉丝告诉您什么)。
ninjalj 2011年

25

在我看来,x86的主要缺点是它的CISC起源-指令集包含许多隐式的相互依赖关系。这些相互依赖性使得很难在芯片上执行诸如指令重新排序之类的事情,因为必须为每个指令保留这些相互依赖性的工件和语义。

例如,大多数x86整数加减指令修改标志寄存器。在执行加法或减法之后,下一步操作通常是查看标志寄存器以检查溢出,符号位等。如果此后还有其他加法,很难判断开始执行第二个加法是否安全在知道第一个加法的结果之前。

在RISC架构上,加法指令将指定输入操作数和输出寄存器,并且有关该操作的所有操作都将仅使用这些寄存器进行。这使得解耦彼此相近的添加操作变得更加容易,因为没有Bloomin'标志寄存器会强制所有内容对齐并执行单个文件。

DEC Alpha AXP芯片是MIPS风格的RISC设计,在可用的指令中痛苦地横冲直撞,但是指令集的设计避免了指令间隐式寄存器的依赖性。没有硬件定义的堆栈寄存器。没有硬件定义的标志寄存器。甚至指令指针也是OS定义的-如果您想返回到调用者,则必须弄清楚调用者将如何让您知道要返回的地址。这通常是由OS调用约定定义的。但是,在x86上,它是由芯片硬件定义的。

无论如何,经过3或4代Alpha AXP芯片设计,硬件已从具有32个int寄存器和32个浮点寄存器的spartan指令集的字面实现变为具有80个内部寄存器,寄存器重命名,结果转发(将前一条指令的结果转发到依赖于该值的后一条指令)以及各种疯狂的性能提升器。有了所有这些优点,AXP芯片管芯仍然比当时的Pentium芯片管芯小得多,而AXP则快得多了。

您不会在x86家族树中看到这种性能提升,这在很大程度上是因为x86指令集的复杂性使许多种执行优化成本高昂,甚至并非不可能。英特尔的天才之处在于不再在硬件中实现x86指令集-所有现代x86芯片实际上都是RISC内核,在一定程度上解释了x86指令,将其翻译为内部微码,从而保留了原始x86的所有语义。指令,但允许对RISC进行一些乱序操作以及对微码的其他优化。

我已经写了很多x86汇编器,并且可以完全理解其CISC根目录的便利性。但是,直到我花一些时间编写Alpha AXP汇编程序后,我才完全意识到x86的复杂性。我对AXP的简单性和统一性感到震惊。差异是巨大而深刻的。


6
我会听不扑CISC的本身,除非及直至你能解释m68k的。
dmckee ---前主持人小猫,2010年

2
我对m68k不熟悉,因此无法对其进行评论。
dthorpe

4
我认为这个答案不足以否决投票,但我确实认为,整个“ RISC比CISC规模更小,速度更快”的论点在现代时代并不重要。可以肯定的是,AXP当时可能快得多了,但事实是,就性能而言,现代RISC和现代CISC几乎相同。就像我在回答中所说的那样,x86解码的轻微功耗是不将x86用于诸如手机之类的原因,但这对于全尺寸的台式机或笔记本电脑来说就不足为奇了。
Billy ONeal 2010年

4
@Billy:大小不仅仅是代码大小或指令大小。英特尔在芯片表面积方面付出了很大的代价,以实现所有这些特殊指令的硬件逻辑,无论是否采用RISC微代码内核。模具的尺寸直接影响制造成本,因此对于现代系统设计而言,它仍然是一个有效的考虑因素。
dthorpe

1
@dthorpe:我不同意您写的大部分内容。自8086年以来,您不必担心执行一次add又一次的安全操作add。规则很明确。您也无需处理指令重新排序。自从90年代中期的Pentium Pro以来,CPU便为您做到了。您所提到的可能是20年前的问题,但我认为现在没有任何理由将其与x86架构相提并论。
弥敦道·菲尔曼

21

x86体系结构可追溯到8008微处理器及其亲戚的设计。这些CPU是在内存速度较慢的时候设计的,如果您可以在CPU裸片上进行操作,通常速度会快很多。但是,CPU模具空间也很昂贵。这两个原因是为什么只有少量的寄存器倾向于特殊用途,以及具有各种陷阱和限制的复杂指令集的原因。

同一时代的其他处理器(例如6502系列)也具有类似的局限性和怪异之处。有趣的是,8008系列和6502系列都打算用作嵌入式控制器。即使在那时,嵌入式控制器仍有望在汇编器中进行编程,并以多种方式迎合汇编程序员而不是编译器作家的需要。(请参见VAX芯片,了解当您迎接编译器编写时发生的情况。)设计人员并不希望它们成为通用计算平台;而是希望它们成为通用计算平台。这就是POWER架构的前身之类的目的。当然,家用计算机的革命改变了这一点。


4
+1是这里似乎唯一具有该问题历史背景的人的唯一答案。
Billy ONeal 2010年

3
记忆一直很慢。今天(相对而言)可能比我在1982年开始使用Z80s和CP / M时要慢。我想说x86在它的28年(到目前为止)已经很好地适应了。
Olof Forshell

4
内存速度在8086左右短暂达到了与CPU相当的水平。德州仪器(Texas Instruments)的9900的设计仅在发生这种情况时才起作用。但是随后,CPU再次运行并停留在那里。直到现在,才有缓存来帮助管理。
staticsan 2010年

3
@Olof Forshell:它与汇编程序兼容,因为8080汇编代码可以转换为8086代码。从这个角度来看,它是8080扩展名,就像您可以将8080视为8008扩展名。
David Thornley,

3
@Olof Forshell:除了8086是为此目的而设计的。它是8080的扩展,并且大多数(可能是全部)8080指令一对一映射,并且具有明显相似的语义。无论您想采用哪种方式推销IBM 360架构,事实并非如此。
David Thornley,

13

我在这里还有其他一些方面:

考虑操作“ a = b / c”,x86将其实现为

  mov eax,b
  xor edx,edx
  div dword ptr c
  mov a,eax

作为div指令的附加好处,edx将包含其余部分。

RISC处理器需要首先加载b和c的地址,将b和c从存储器加载到寄存器,进行除法并加载a的地址,然后存储结果。Dst,src语法:

  mov r5,addr b
  mov r5,[r5]
  mov r6,addr c
  mov r6,[r6]
  div r7,r5,r6
  mov r5,addr a
  mov [r5],r7

在这里通常不会有剩余。

如果要通过指针加载任何变量,尽管RISC的可能性较小,但两个序列都可能变长,因为RISC可能已经在另一个寄存器中加载了一个或多个指针。x86的寄存器较少,因此指针位于其中之一的可能性较小。

利弊:

RISC指令可以与周围的代码混合以改善指令调度,而x86则不太可能这样做,而x86可以在CPU本身内部完成此工作(或多或少取决于顺序)。上面的RISC序列在32位体系结构上通常为28个字节长(每条7个指令,每个32位/ 4个字节宽度)。这将导致片外存储器在提取指令时(七次提取)工作更多。更密集的x86序列包含较少的指令,尽管它们的宽度有所不同,但您可能也正在查看平均每个指令4个字节。即使您具有指令高速缓存来加快这七个访存的速度,这也意味着与x86相比,您将在其他地方弥补三个不足。

x86体系结构具有更少的要保存/恢复的寄存器,这意味着它可能比RISC更快地执行线程切换和处理中断。要保存和还原更多的寄存器,需要更多的临时RAM堆栈空间来执行中断,并需要更多的永久堆栈空间来存储线程状态。这些方面应该使x86成为运行纯RTOS的更好的选择。

从个人角度来说,我发现编写RISC程序集比x86更加困难。我通过用C编写RISC例程,编译和修改生成的代码来解决此问题。从代码生产的角度来看,这效率更高,从执行角度来看,效率可能更低。所有这32个寄存器都需要跟踪。使用x86则是另一种方式:6-8个带有“真实”名称的寄存器使问题更易于管理,并且使人们更有信心产生的代码将按预期工作。

丑陋?这在情人眼中。我更喜欢“不同”。


在我的示例中,a,b和c应该被视为基于内存的变量,而不是立即数。
Olof Forshell 2010年

...“ dword ptr”用于指定一个变量的大小,该变量的大小例如在被简单地声明为外部变量或懒惰时未知。
Olof Forshell

2
这不是我第一次听到建议先用C编写然后提炼成汇编程序的建议。那肯定是有帮助
乔·普兰特

在早期,所有处理器都是RISC。CISC是针对非常慢的铁芯内存系统的缓解策略,因此CISC的指令更少,功能更强大,对内存子系统的压力较小,并且可以更好地利用带宽。同样,寄存器最初被认为是用于进行累加的片上CPU内部存储器位置。我上次认真评估RISC计算机的基准是1993年-SPARC和HP Prisim。SPARC全面令人恐惧。Prisim在add / sub / mul中的速度是486的20倍,但在先验技术上却很烂。CISC更好。

@OlofForshell您说过,there typically won't be a reminder但Wiki上说,它具有一些技巧:en.wikipedia.org/wiki/MIPS_instruction_set#Integer
Alex Zhukovskiy

10

我认为这个问题有一个错误的假设。主要是RISC痴迷的学者称x86为丑陋。实际上,x86 ISA可以在一条指令中完成操作,而在RISC ISA上需要5-6条指令。RISC爱好者可能会反驳说,现代的x86 CPU将这些“复杂的”指令分解为微指令。然而:

  1. 在许多情况下,这只是部分正确或根本不正确。x86中最有用的“复杂”指令是诸如mov %eax, 0x1c(%esp,%edi,4)寻址模式之类的东西,并且这些没有细分。
  2. 在现代机器上通常更重要的不是花费的周期数(因为大多数任务不是cpu绑定的),而是代码对指令缓存的影响。5-6个固定大小(通常为32位)的指令对缓存的影响将远远大于一条很少超过5个字节的复杂指令。

x86真正吸收了大约10-15年前的RISC的所有优点,而RISC的其余质量(实际上是定义性的 -最小指令集)是有害的和不受欢迎的。

除了制造CPU的成本和复杂性及其能耗要求之外,x86是最佳的ISA。否则,任何告诉您的人都会让意识形态或议程妨碍他们的推理。

另一方面,如果您将目标放在CPU成本至关重要的嵌入式设备上,或者将能耗放在首位的嵌入式/移动设备上,则ARM或MIPS可能更有意义。请记住,尽管您仍然需要处理额外的ram和二进制大小,以处理轻松地大3-4倍的代码,并且您将无法获得接近的性能。这是否重要在很大程度上取决于您将在其上运行什么。


3
在能耗是头等大事的情况下,ARM或MIPS可能更有意义 ...那么,如果至少有一个方面使ARM或MIPS更有意义,这是否会使x86 不一定是最好的ISA?
Shahbaz

这就是为什么我将“除成本...及其能源需求之外”评为“最佳”。
R .. GitHub停止帮助ICE

1
我认为英特尔正在限制CPU速度,较小的裸片尺寸已在很大程度上消除了功耗差异。带有64k L1和1MB L2高速缓存的新型赛扬双64位CPU是7.5瓦芯片。这是我的“星巴克”视频群聊机器,电池寿命非常长,并且会在P6机器周围响动。作为一个主要从事浮点计算的人,我很久以前就放弃了RISC。它只是爬行。SPARC特别是冰河。RISC为何失败的完美示例是Intel i860 CPU。英特尔再也没有去过那里。

@RocketRoy:对于24/7供电(并且一直没有执行有用的计算)或用3.7v / 2000mAh电池供电的设备,实际上不接受7.5瓦功率。
R .. GitHub停止帮助ICE

2
@RocketRoy “英特尔i860 CPU。英特尔再也没有出现过。” 一个小小的研究后,1860听起来很多 VLIW,编译器排序指令并行....:像安腾
乔纳森·莱因哈特

9

x86汇编语言还不错。当您接触到机器代码时,它开始变得非常丑陋。指令编码,寻址模式等比大多数RISC CPU的要复杂得多。为了向后兼容目的,还内置了额外的乐趣-这些东西只有在处理器处于特定状态时才会出现。

例如,在16位模式下,寻址似乎很奇怪。有一种寻址方式[BX+SI],但没有一种[AX+BX]。诸如此类的事情会使寄存器的使用变得复杂,因为您需要确保您的值位于可以根据需要使用的寄存器中。

(幸运的是,32位模式要聪明得多(尽管有时它本身仍然有些怪异-例如分段),而在引导加载程序和某些嵌入式环境之外,16位x86代码不再重要。)

过去,英特尔试图使x86成为最终处理器时,还有一些遗留的东西。指令长了几个字节,执行的任务实际上没有人再执行,导致坦率地说它们太慢或太复杂。对于两个示例,请参见 ENTER和LOOP指令 -注意,对于大多数编译器,C堆栈帧代码就像“ push ebp; mov ebp,esp”,而不是“ enter”。


2
我认为出现“输入”与“推送/移动”问题是因为在某些处理器上,“推送/移动”更快。在某些处理器上,“输入”速度更快。这就是生活。
Dietrich Epp 2010年

4
当我被迫使用基于x86的计算机并开始查看它(具有m68k背景)时,我开始感到asm编程令人沮丧,就像我已经学会了使用C语言一样,然后被迫与asm联系...您“感觉”到失去表达,轻松,清晰,“连贯”,“直觉”的能力。我相信,如果我会使用x86开始asm编程,我会想到并没有那么糟糕...也许...我也做了MMIX和MIPS,它们的“ asm lang”远胜于x86(如果这是Q的正确PoV,但也许不是)
ShinTakezou

80386中解决了寻址模式问题。只有16位代码具有受限的寻址模式,而32位代码要好得多。您可以使用特殊的前缀以16位代码获得32位寻址模式,反之亦然。
2015年

@FUZxxl:是的...我可能应该提到丑陋主要限于16位代码。固定(我认为)。:)
cHao 2015年

显而易见的高明之处主要是由于人们误解了8086的寄存器是通用寄存器。那是不对的。他们每个人都有特殊的目的,如果您不遵守他们的目的,那将是一段糟糕的时光。
2015年

3

我不是专家,但似乎很多人不喜欢它的功能可能就是它表现出色的原因。几年前,拥有寄存器(而不是堆栈),寄存器框架等被认为是使体系结构对人类来说更简单的不错的解决方案。但是,如今,重要的是缓存性能,并且x86的可变长度字允许它在缓存中存储更多指令。我相信对手曾经指出,“指令解码”占据了一半的筹码,现在已经不再那么重要了。

我认为并行性是当今最重要的因素之一-至少对于已经足够快地运行以使其可用的算法而言。在软件中表达高并行度允许硬件分摊(或通常完全隐藏)内存延迟。当然,更遥远的体系结构未来可能在诸如量子计算之类的领域。

我从nVidia听到,英特尔的错误之一是它们使二进制格式与硬件保持接近。CUDA的PTX可以进行一些快速的寄存器使用计算(图形着色),因此nVidia可以使用寄存器计算机而不是堆栈计算机,但是升级路径不会破坏所有旧软件。


9
RISC设计时并未考虑人类开发人员。RISC背后的想法之一是将芯片的某些复杂性转移给编写程序集的人,最好是编译器。更多的寄存器意味着更少的内存使用和更少的指令间依赖性,从而允许更深的流水线和更高的性能。请注意,x86-64的通用寄存器是x86的两倍,仅此一项就可以显着提高性能。而且大多数x86芯片上的指令都是在缓存之前解码的,而不是在之后解码的(因此大小在这里无关紧要)。
Dietrich Epp 2010年

3
@Dietrich Epp:并非完全如此。x86-64的确在ISA中具有更多可见的寄存器,但是现代的x86实现通常具有RISC样式的寄存器文件,该文件按需映射到ISA的寄存器以加快执行速度。
Billy ONeal

“我从nVidia听到,英特尔的错误之一是它们使二进制格式与硬件保持接近。” -我没有得到这和CUDA的PTX部分。
爪子

1
@Dietrech Epp:“而且大多数x86芯片上的指令都是在缓存之前解码的,而不是在之后解码的”,那是不对的。它们在被解码之前被缓存。我相信Pentium 4还有一个额外的跟踪缓存,该缓存在解码后会缓存,但是已经停产了。
内森·费尔曼

事实并非如此,最新的“桑迪桥”处理器使用了一种跟踪缓存(例如奔腾4的缓存,哦,那个老男孩:D),因此技术消失了,然后又回来了……
Quonux

3

除了人们已经提到的原因之外:

  • x86-16有一个很奇怪的内存寻址方案,该允许以多达4096种不同的方式对单个内存位置进行寻址,将RAM限制为1 MB,并迫使程序员处理两种不同大小的指针。幸运的是,转移到32位使此功能变得不必要,但是x86芯片仍然保留了段寄存器的功能。
  • 虽然不是一个错误的x86 本身,x86的调用约定不规范像MIPS是(主要是因为MS-DOS没有附带任何编译器),留给我们的烂摊子__cdecl__stdcall__fastcall,等。

嗯..当我想到x86竞争对手时,我没有想到MIPS。也许是ARM或PowerPC ....
Billy ONeal 2010年

@Billy:x86已经永远存在了。MIPS曾经是x86的竞争对手。我记得x86的工作量已达到与MIPS竞争的水平。(早在MIPS和SPARC在工作站领域进行对抗时。)
Shannon Severance 2010年

@Shannon遣散费:仅仅因为曾经有过某事并不意味着那是过去。
Billy ONeal 2010年

2
@supercat:扁平x86-32内存模型时代的人们往往会忘记的是16位意味着64k内存(任何打扰数学的人都会明白魔术是不可能的,8086不是对毫无戒心的程序员的严厉惩罚)。几乎没有办法获得64k,但是8086解决方案是一个很好的折衷方案。
Olof Forshell

2
@OlofForshell:我认为许多人都为8086不如68000(具有16MB的线性寻址空间和通向4个演出的清晰路径)而抱怨。当然,使用32位处理器将使其更易于访问超过64K,但8086是16位体系结构,其设计是从8位8080的基础上发展的。直接从8位转换为32位。
2013年

3

我认为,如果您尝试编写针对x86的编译器,或者编写x86机器仿真器,或者即使尝试在硬件设计中实现ISA,也将获得部分答案。

虽然我了解“ x86很难看!” 论点,我仍然认为编写x86程序集比MIPS 更有趣(例如MIPS),后者简直乏味。它始终意味着对编译器好,而不是对人类好。我不确定如果尝试的话,芯片是否会对编译器编写者更具敌意...

对我来说,最糟糕的部分是(实模式)分段的工作方式-任何物理地址都具有4096 segment:offset别名。您上一次需要什么?如果段部分严格是32位地址的高阶位,那么事情会简单得多。


如果正确的PoV是人类可以在这些程序集中编写代码的方式,则m68k会更有趣,并且对人类的好处远不止x86(对于许多m68k程序员而言,这似乎不那么“人类”)。
ShinTakezou

segment:offset寻址是在某种程度上保持与CP / M世界兼容的尝试。有史以来最糟糕的决定之一。
图灵完成了2010年

@Turing Complete:segment:offset主要不是试图与CP / M世界保持兼容。这是一次非常成功的尝试,它允许16位处理器通过将代码,数据,堆栈和其他内存区域放置在不同的段中来寻址超过64 KB。
Olof Forshell

1
实际上,将数据和堆栈放在不同的段中对于C完全没有用;它仅适用于asm。在C语言中,指针可以指向具有静态,自动或动态分配的存储持续时间的数据,因此无法消除该段。也许它是从Pascal或Fortran或一些有用的东西,但不能用于C,这已经是当时的主流语言...
R.,GitHub上停止帮助ICE

2
@伯恩德:之所以选择fs / gs进行线程本地存储,并不是因为段寄存器对此有用。只是x86严重缺乏寄存器,而段寄存器未使用。指向线程结构的通用寄存器也可以正常工作,实际上,许多具有更多寄存器的RISC系统都将其中一个用作线程指针。
R .. GitHub停止帮助ICE,

1
  1. x86的通用寄存器非常有限

  2. 它会在最低级别(CISC地狱)上推广非常低效的开发风格,而不是有效的加载/存储方法

  3. 英特尔做出了令人震惊的决定,推出了显而易见的愚蠢的段/偏移-内存地址模型,以与(目前已经!)过时的技术保持兼容。

  4. 在每个人都使用32位的时候,x86仅有16位(大多数都是8088,甚至只有8位外部数据路径,这甚至更吓人!),从而在主流PC世界中占据了主导地位。


对我来说(第3点)是最糟糕的情况(我是DOS的资深人士,从开发人员的角度看过每一代PC!)。

想象一下90年代初(主流!)的以下情况:

a)由于遗留原因而受到疯狂限制的操作系统(640kB的易于访问的RAM)-DOS

b)操作系统扩展(Windows)可以在RAM方面做更多的工作,但是在游戏等东西上却受限制……而且它不是地球上最稳定的东西(幸运的是后来发生了变化,但是我在这里谈论90年代初

c)大多数软件仍然是DOS,我们不得不经常为特殊软件创建启动盘,因为有些程序喜欢这个EMM386.exe,其他程序讨厌(特别是游戏玩家-我当时是AVID玩家-知道我在这里谈论)

d)我们仅限于使用MCGA 320x200x8位(好的,还有更多特殊技巧,可以进行360x480x8的操作,但只有在不支持运行时库的情况下),其他一切都是混乱和可怕的(“ VESA”-大声笑)

e)但是就硬件而言,我们有32位计算机,具有相当大的RAM和VGA卡,支持高达1024x768

造成这种情况的原因是什么?

英特尔的简单设计决定。机器指令级(不是二进制级!)与已经濒临崩溃的产品的兼容性,我认为它是8085。其他看似无关的问题(图形模式等)由于技术原因和非常狭窄的问题而相关。 x86平台自带的架构。

今天,情况有所不同,但是请问任何汇编程序开发人员或为x86构建编译器后端的人员。通用寄存器的数量如此之少,无非是可怕的性能杀手。


8086分段体系结构的唯一主要问题是只有一个非专用分段寄存器(ES),并且没有设计编程语言来有效地使用它。它使用的缩放寻址方式在面向对象的语言中会很好地工作,这种语言不希望对象能够从任意地址开始(如果将对象对齐到段落边界,则对象引用将仅需要两个字节,而不是四)。如果将早期的Macintosh代码与PC代码进行比较,则与68000相比,8086实际上看起来还不错。–
supercat

@supercat:实际上,es寄存器专门用于某种东西,即那些需要存储(移动,存储)或扫描(cmps和scas)的字符串指令。给定每个段寄存器的64KiB寻址,es还为除代码,数据和堆栈存储器(cs,ds,ss)之外的存储器提供了“缺失链接”。段寄存器提供了一种内存保护方案,因为您无法在寄存器的64Kib内存块之外进行寻址。考虑到x86是16位体系结构并且受到当今的光刻限制,您提出什么更好的解决方案?
Olof Forshell

@OlofForshell:ES用于字符串指令,但可以用作未使用它们的代码的未提交寄存器。在不需要太多操作码空间的情况下缓解seg-reg瓶颈的一种方法是使用“ rseg”前缀,该前缀将指定对于以下r / m格式指令,“ r”字段将从CS / SS / DS中选择/ ES / FS / GS / ?? / ?? 而不是AX / BX / CX / DX / SI / DI / SP / BP,并带有FS / GS前缀和LFS和LGS指令(如LDS和LES)。我不知道8086的微体系结构是如何布置的,但我认为类似的方法可能会起作用。
超级猫

@supercat:正如我写的,“寄存器es还提供了到内存的丢失链接,而不是...”,直到我记得386为止,FS和gs才到。
Olof Forshell

1
@OlofForshell:他们没有这样做,这使得80286架构在大多数方面都比8086架构差。我的观点是,添加更多的段寄存器(就此而言,甚至是一个)将使8086体系结构更加有用,并且如果像其他的。
supercat
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.