我看到如下代码:
mov ax, cs
mov ds, ax
mov es, ax
为什么我不能将其压缩为:
mov ds, cs
mov es, cs
自从使用累加器寄存器以来,第一种方法是否更快?但这似乎并不直观,因为 cs 和 ds 是段寄存器。还是有一些我不知道的限制?
顺便说一句,我正在使用nasm。
我看到如下代码:
mov ax, cs
mov ds, ax
mov es, ax
为什么我不能将其压缩为:
mov ds, cs
mov es, cs
自从使用累加器寄存器以来,第一种方法是否更快?但这似乎并不直观,因为 cs 和 ds 是段寄存器。还是有一些我不知道的限制?
顺便说一句,我正在使用nasm。
你不能将段寄存器移动到段寄存器——没有指令。
处理器中用于所有指令的微码只有这么多空间。因此,对于很少使用的操作湖更改段寄存器,通常首选一条通用指令而不是几条专用指令。此外,对于某些处理器,指令的数量绝对受到架构的限制——例如,最初的 8080 处理器被限制为 256 条指令,因为它们都必须将操作码编码在一个字节中。
查看英特尔手册第 2 卷指令集参考 - 325383-056US 2015 年 9 月“MOV 移动”列“指令”。
寄存器的唯一 16 位 mov 编码为:
mov r/m16, Sreg
而《3.1.1.3 操作码汇总表中的指令列》解释:
因此mov ds, cs
是不可编码的,因为没有mov Sreg, Sreg
版本。
真正阻止这些操作的不是汇编语言,而是底层机器语言。
虽然汇编由易于阅读的单词或助记符组成,但它们实际上非常直接地表示机器代码的 1 和 0。在 x86 CPU 上,每条指令通常由一系列字节组成,其中各个字节甚至是字节中的位都有意义。某些位代表指令,其他位代表寻址模式。在诸如您的示例之类的寄存器寻址模式中,一些位表示将哪些特定寄存器用作mov
指令的源和目标。
现在,x86 系列处理器可以追溯到 1970 年代,当时 CPU 架构更简单。在那些日子里,累加器的概念非常重要 -ax
是 16 位 x86 累加器。所有计算都在此寄存器中建立或“累积”,因此可用于所有指令。其他通用寄存器的使用范围更受限制。
因为指令是基于字节的,所以您希望尽可能少的字节来表示一条指令,以保持指令解码的快速。为了使尽可能多的指令尽可能短,累加器的使用成为中心。
在摩托罗拉 680x0 等更现代的 CPU 上,更多通用寄存器具有更多以前属于累加器领域的能力。在 RISC CPU 上,所有寄存器都像累加器一样灵活。我听说在 64 位模式下,当前的 x86/amd64 指令集现在受到的限制要少得多。