cla*_*aws 101 x86 assembly x86-64 mips cpu-architecture
最近我一直在阅读一些SO档案,并遇到了针对x86架构的声明.
为什么我们需要不同的CPU架构用于服务器和迷你/大型机和混合核心?他说:
" PC架构一团糟,任何操作系统开发人员都会告诉你. "
学习汇编语言值得努力吗?(存档)说
"意识到x86架构充其量是可怕的 "
学习x86汇编程序的任何简单方法?他说:
" 大多数大学都教MIPS之类的装配,因为它更容易理解,x86装配非常难看 "
还有更多的评论
我试过搜索,但没有找到任何理由.我发现x86不好可能因为这是我熟悉的唯一架构.
有人可以给我一些考虑x86丑陋/坏/劣等的理由.
Bil*_*eal 89
几个可能的原因:
IN及OUT)x86汇编代码很复杂,因为x86是一个具有许多功能的复杂架构.典型MIPS机器的说明列表适合单个字母大小的纸张.x86的等效列表填写了几页,而且说明只是做了更多,所以你经常需要一个比列表可以提供的更多的解释.例如,MOVSB指令需要一个相对较大的C代码块来描述它的作用:
if (DF==0)
*(byte*)DI++ = *(byte*)SI++;
else
*(byte*)DI-- = *(byte*)SI--;
Run Code Online (Sandbox Code Playgroud)
这是一个执行加载,存储和两个加法或减法(由标志输入控制)的指令,每个指令都是RISC机器上的单独指令.
虽然MIPS(和类似架构)的简单性并不一定使它们更优越,但是对于汇编类汇编课程的教学,从更简单的ISA开始是有意义的.一些汇编类教导了一个名为y86的超简化x86子集,它被简化为超出了对实际使用无用的点(例如没有移位指令),或者一些只教授基本的x86指令.
编辑:这不应该是一个bash x86!派对.考虑到问题的措辞,我别无选择,只能进行一些抨击.但除了(1)之外,所有这些事情都是有充分理由的(见评论).英特尔设计师并不愚蠢 - 他们希望通过他们的架构来实现一些东西,而这些是他们为实现这些目标而必须付出的一些税.
dth*_*rpe 25
在我看来,对x86的主要打击是它的CISC起源 - 指令集包含许多隐含的相互依赖性.这些相互依赖性使得难以对芯片上的指令重新排序这样做,因为必须为每个指令保留这些相互依赖性的工件和语义.
例如,大多数x86整数加法和减法指令修改了标志寄存器.在执行加或减之后,下一个操作通常是查看标志寄存器以检查溢出,符号位等.如果之后有另一个添加,则很难判断开始执行第二个添加是否安全在第一次添加的结果已知之前.
在RISC架构中,add指令将指定输入操作数和输出寄存器,并且仅使用那些寄存器进行有关操作的所有操作.这使得分离彼此接近的添加操作变得更加容易,因为没有bloomin'标志注册强制所有内容排队并执行单个文件.
DEC Alpha AXP芯片是一种MIPS风格的RISC设计,在可用指令中非常简洁,但指令集旨在避免指令间隐式寄存器依赖性.没有硬件定义的堆栈寄存器.没有硬件定义的标志寄存器.甚至指令指针也是操作系统定义的 - 如果你想返回调用者,你必须弄清楚调用者将如何让你知道要返回的地址.这通常由OS调用约定定义.但是在x86上,它是由芯片硬件定义的.
无论如何,超过3或4代Alpha AXP芯片设计,硬件从具有32个int寄存器和32个浮点寄存器的spartan指令集的文字实现变为具有80个内部寄存器的大规模乱序执行引擎,寄存器重命名,结果转发(将前一条指令的结果转发给后来依赖于该值的指令)以及各种狂野和疯狂的性能提升器.所有这些花里胡哨的东西,AXP芯片芯片仍然比当时的奔腾芯片芯片小得多,而AXP的速度要快得多.
你不会在x86系列树中看到那些性能提升的东西很大程度上是因为x86指令集的复杂性使得许多类型的执行优化成本过高,如果不是不可能的话.英特尔的天才是放弃在硬件上实现x86指令集 - 所有现代x86芯片实际上都是RISC核心,在某种程度上解释了x86指令,将它们转换为内部微码,保留了原始x86的所有语义指令,但允许一点RISC乱序和微码的其他优化.
我编写了很多x86汇编程序,可以充分理解其CISC根本的便利性.但是我没有完全理解x86是多么复杂,直到我花了一些时间编写Alpha AXP汇编程序.我对AXP的简洁和统一感到惊讶.差异是巨大而深刻的.
sta*_*san 20
x86架构可以追溯到8008微处理器和亲属的设计.这些CPU是在内存缓慢的时候设计的,如果你可以在CPU裸片上进行设计,它通常要快得多.但是,CPU芯片空间也很昂贵.这两个原因是为什么只有少数寄存器具有特殊用途,以及具有各种陷阱和限制的复杂指令集.
来自同一时代的其他处理器(例如6502系列)也有类似的限制和怪癖.有趣的是,8008系列和6502系列都是嵌入式控制器.即使在那时,嵌入式控制器也可以用汇编程序进行编程,并且在很多方面都适合汇编程序员而不是编译器编写器.(看看VAX芯片,当你迎合编译器编写时会发生什么.)设计人员不希望它们成为通用计算平台; 那就像POWER架构的前辈那样.当然,家庭计算机革命改变了这一点.
Olo*_*ell 12
我还有一些其他方面:
考虑操作"a = b/c"x86将其实现为
mov eax,b
xor edx,edx
div dword ptr c
mov a,eax
Run Code Online (Sandbox Code Playgroud)
作为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
Run Code Online (Sandbox Code Playgroud)
这里通常不会有余数.
如果要通过指针加载任何变量,则两个序列可能会变长,尽管这对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个具有"真实"名称的寄存器使问题更易于管理,并使得生成的代码能够按预期工作更有信心.
丑陋?这是旁观者的眼睛.我更喜欢"与众不同".
我认为这个问题有一个错误的假设.它主要是只有RISC痴迷的学者称x86丑陋.实际上,x86 ISA可以在单个指令操作中执行,这将在RISC ISA上执行5-6条指令.RISC粉丝可能会反驳现代x86 CPU将这些"复杂"指令分解为microops; 然而:
mov %eax, 0x1c(%esp,%edi,4)就是寻址模式,这些都没有细分.x86在10 - 15年前真正吸收了RISC的所有优点,RISC的其余特性(实际上是定义的 - 最小指令集)是有害的,也是不可取的.
除了制造CPU的成本和复杂性及其能源需求外,x86是最好的ISA.任何告诉你的人都会让意识形态或议程妨碍他们的推理.
另一方面,如果您的目标是CPU成本高的嵌入式设备,或者能耗最受关注的嵌入式/移动设备,ARM或MIPS可能更有意义.请记住,虽然你仍然需要处理处理代码所需的额外内存和二进制大小,这些代码很容易大3-4倍,但你将无法接近性能.这是否重要取决于您将在其上运行的内容.
x86汇编语言并不是那么糟糕.当你到达机器代码时,它开始变得非常难看.指令编码,寻址模式等比大多数RISC CPU复杂得多.为了向后兼容的目的,内置了额外的乐趣 - 只有当处理器处于特定状态时才会启动.
例如,在16位模式中,寻址看起来很奇怪; 有一种寻址模式[BX+SI],但不是一种[AX+BX].这样的事情往往会使寄存器的使用变得复杂,因为您需要确保您的值在您可以根据需要使用的寄存器中.
(幸运的是,32位模式更加安全(虽然有时候仍然有点奇怪 - 例如分段),并且16位x86代码在引导加载程序和某些嵌入式环境之外已经基本上无关紧要了.)
还有来自过去的剩余时间,当时英特尔试图让x86成为终极处理器.说明几个字节长,执行任何人实际上不再执行的任务,因为他们坦率地说太慢或者复杂.对于两个示例,请参阅ENTER和LOOP指令 - 注意C堆栈帧代码类似于"push ebp; mov ebp,esp",而不是大多数编译器的"输入".
| 归档时间: |
|
| 查看次数: |
26033 次 |
| 最近记录: |