问题
I decided to learn an assembly programming language. I am using this 8086 tutorial. At the bottom the exercise is to find an error in some instructions and one of them is
mov cx, ch
I found some similar question on SO on this topic explaining how to achieve it but now I'd like to know why this operation is forbidden?
Let's assume I have 10d = 00001010b in CH and want to put it to CL and simultaneously erase CH. mov cx, ch seems to do it because it shows 10d as 16bit 00000000 00001010 and puts it respectively to CH and CL (entire CX)
What is wrong with it and why does given tutorial ask to find an error in this expression?
回答1:
The mov instruction is used to move between operands of the same size. What you want to is extend the 8-bit ch into the 16-bit cx. There are two instructions available for that purpose:
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
Another way of accomplishing the same thing in this particular case would be:
shr cx,8 ; zero-extend
sar cx,8 ; sign-extend
回答2:
The problem is, that you're trying to move the contents of an 8 bit register ch into a 16 bit register cx. You can't do that because the registers are different sizes.
So I'd guess that you get an error message like "invalid combination of opcode and operands".
p.s: exchanged 8 and 16 above; the statement stays the same. Check for instance this overview. As you see, there is no combination of different register sizes defined. It means there doesn't exist any OPcode that represents mov cx, ch.
回答3:
You want to move the contents of CH to CX on an 8086.
On more recent processors, such as the 80286, you could just shift the value of CX right by 8 positions, with or without sign replication:
; zero extend ch into cx
shr cx,8
; sign extend ch into cx
sar cx,8
These instructions are not available on the 8088 or the 8086. You can must use CL to specify the shift count:
; zero extend ch into cx
mov cl,8
shr cx,cl
; sign extend ch into cx
mov cl,8
sar cx,cl
Yet this method is very slow because the shift by a variable number of positions takes multiple cycles per position.
Here is a faster method:
; 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
If you can destroy AX, you can save code size by using cbw which is designed for this. On original 8086 and especially 8088, small = fast because code fetch was a major bottleneck. That's not true on modern x86, though.
; 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
To avoid destroying AX, you could do mov cl,ch ; xchg ax,cx ; cbw and stop there, or do a final xchg ax,cx to just sign-extend CH into CX and restore everything else. xchg with AX is a 1-byte instruction, and so is cbw and cwd (extend AX into DX:AX, e.g. before 16-bit idiv)
cbw is exactly like 386 movsx ax, al.
回答4:
just do it with simple instructions
mov cl,ch ; copy high bits to low
xor ch,ch ; clear high-bits
it is common in 16bit programming and it only takes 2 clock cycles.
The use of the movezx/movsx needs 3 clock cycles. Use
movsx cx,ch
for moving byte to word with sign-extension and
movzx cx,ch
to Move byte to word with zero-extension
来源:https://stackoverflow.com/questions/29716796/masm-assembly-move-8-bit-register-to-the-16-bit-register-ie-mov-cx-ch