我决定学习汇编编程语言。我正在使用this。在底部练习它在一些指令中找到错误,其中之一是
mov cx, ch
我在这个主题上发现了一些关于如何实现它的类似问题,但现在我想知道为什么禁止这种操作?
假设我在CH中有10d = 00001010b并且想要将其置于CL并同时擦除CH。 mov cx, ch
似乎是这样做的,因为它将10d显示为16bit 00000000 00001010并将其分别放入CH和CL(整个CX)
它有什么问题,为什么给定的教程要求在这个表达式中找到错误?
答案 0 :(得分:5)
mov
指令用于在相同大小的操作数之间移动。你想要的是将8位ch
扩展到16位cx
。有两个指令可用于此目的:
movzx cx,ch ; zero-extends ch into cx. the upper byte of cx will be filled with zeroes
movsx cx,ch ; sign-extends ch into cx. the upper byte of cx will be filled with the most significant bit of ch
在这种特殊情况下完成同样事情的另一种方法是:
shr cx,8 ; zero-extend
sar cx,8 ; sign-extend
答案 1 :(得分:2)
问题是,您正试图将8位寄存器ch
的内容移动到16位寄存器cx
中。你不能这样做,因为寄存器的大小不同。
所以我猜你会收到一条错误消息,例如“操作码和操作数的无效组合”。
p.s :上面交换了8和16;声明保持不变。检查实例this overview。如您所见,没有定义不同寄存器大小的组合。这意味着不存在任何代表mov cx, ch
的OPcode。
答案 2 :(得分:2)
您要在8086上将CH
的内容移动到CX
。
在更新的处理器(例如80286)上,您可以将CX
的值向右移动8个位置,无论是否复制符号:
; zero extend ch into cx
shr cx,8
; sign extend ch into cx
sar cx,8
这些说明在8088或8086上不可用。您必须使用CL
来指定班次计数:
; zero extend ch into cx
mov cl,8
shr cx,cl
; sign extend ch into cx
mov cl,8
sar cx,cl
但是此方法非常慢,因为每个位置可变数量的移位需要多个周期。
这是一种更快的方法:
; zero extend ch into cx
mov cl,ch
xor ch,ch
; sign extend ch into cx
mov cl,ch
neg ch ; set the carry flag if ch is negative
sbb ch,ch ; set all bits if ch was negative, clear them otherwise
如果可以销毁AX,则可以使用为此目的设计的cbw
来节省代码大小。在原始8086尤其是8088上,小=快速,因为代码获取是主要瓶颈。但是,在现代x86上并非如此。
; sign extend ch into ax
mov al, ch
cbw ; sign-extend AL into AX
; optionally move back to cx
xchg cx, ax ; smaller than mov cx, ax
为避免破坏AX,可以执行mov cl,ch
; xchg ax,cx
; cbw
并停在那里,或者执行最后的xchg ax,cx
来将CH符号扩展到CX并恢复其他所有内容。 xchg
和AX是1字节指令,cbw
和cwd
也是如此(将AX扩展为DX:AX,例如在16位idiv
之前)
cbw
就像386 movsx ax, al
。
答案 3 :(得分:0)
只需用简单的说明进行操作
mov cl,ch ; copy high bits to low
xor ch,ch ; clear high-bits
在16位编程中很常见,只需 2个时钟周期。
使用movezx / movsx需要 3个时钟周期。使用
movsx cx,ch
使用 s ign-extension和
将字节移动到字movzx cx,ch
使用 z ero-extension
将字节移动到单词