4

Im trying to find an instruction that will replace MOVZX, since I'm using EMU8086 (which emulates an 8086 that does not support MOVZX).

The closest instruction I found was CBW, which puts the value in the register AX, but it's for signed values only. I need something that will work for unsigned values.

What are my options? Is it possible to do it with a single instruction?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 2
    You can synthesize it from 2 instructions by clearing the top 8 bits of the target register. Such as `mov al, [foo]; mov ah, 0` can replace `movzx ax, [foo]` (there are various ways to clear the top 8 bits of course). – Jester Jul 11 '15 at 13:14
  • Zero out the destination register prior to loading the subregister with the contents of the effective address. – IInspectable Jul 11 '15 at 13:16
  • yeah but the thing is that i need to do it in 1 command line – TotalyNotUbisoft Jul 11 '15 at 13:19
  • 5
    In general, you can't (unless you know the top 8 bits of the target register are already zero). If it were possible, they wouldn't have introduced the movzx instruction. – Jester Jul 11 '15 at 13:23
  • Even if there was a non signed version of cbw, it wouldn't help. For 8086 cbw sign extends al into ax, you'd still need an instruction to load al from memory. – rcgldr Jul 12 '15 at 00:18
  • Why do you need such a thing? Do it with two instructions. – davmac Jan 06 '17 at 15:33
  • @davmac I need to do that in order to shorten my code. – TotalyNotUbisoft Jan 06 '17 at 17:30
  • 2
    Is there a reason you have to shorten your code? Are you trying to solve some other problem by shortening it? Or is it what is required for an assignment? – Michael Petch Jan 06 '17 at 18:26
  • @TotalyNotUbisoft you would likely do better by posting a larger portion of code and asking what could be done to make it shorter. Focusing on this one instruction [sequence] is not going to get you very far, I think. – davmac Jan 06 '17 at 18:50

1 Answers1

4

The movzx instruction zero-extends a value with a smaller width to fit into a larger-width register. For example, movzx would be used to move a 16-bit value into a 32-bit register. (It is contrast to movsx, which does the same thing except with sign extension. You would use movzx when the value is unsigned, and movsx when the value is signed.)

As you point out, these instructions were not introduced until the 386, so if you're targeting an earlier generation of processor, then you'll need to find an alternative.


The basic strategy is, as others pointed out in the comments, to zero the destination register first, and then move the smaller value in. This will accomplish exactly the same thing as movzx. The obvious way to zero a register is with mov reg, 0, but it is smaller and faster to do it using xor reg, reg. Therefore, code like:

movzx  edx, WORD PTR [bx]

can be replaced with:

xor    edx, edx
mov    dx,  WORD PTR [bx]

On modern processors, this is slower than movzx, but it will actually be faster on the 386 and 486, where movzx is relatively slow. And of course, on processors where movzx doesn't exist, you have no choice. You can further minimize the cost by issuing the xor instruction earlier, interspersing it amongst other code.


One significant disadvantage of this approach is that you cannot do an in-place zero-extension on a value stored in a register. That is, there is no way to use this trick when you have code like:

movzx  edx, dx

Instead, you would have to use a temporary register:

xor  eax, eax
mov  ax,  dx
mov  dx,  ax    ; optional, if you really needed the result to be in DX


Or, if you were zero-extending an 8-bit value, you could take advantage of the fact that the upper and lower 8-bit halves of a 16-bit register can be accessed independently on x86, and simply zero the upper 8 bits. For example:

mov    al, BYTE PTR [bx]
xor    ah, ah
; now read from value in AX

Note that this works for in-place zero-extension—just zero the high 8 bits. However, this technique cannot be used to zero-extend a 16-bit value, since there is no way to access just the upper 16 bits of a 32-bit register.


Fortunately, the need for zero-extension on these older architectures is much less than it is on modern architectures, since you don't have to guard as vigorously against partial-register stalls and false dependencies.


In comments, the concern was raised that all of the alternatives to movzx require more than one instruction. Of course, that is true. If there were a way to do it in a single instruction, there wouldn't have been a need for the 386 to introduce movzx. If you're worried about execution speed, consider what I said above that xor+mov will be equally as fast as movzx would have been if it were available, if not faster.

If you're worried about number of instructions, then rest assured that less code does not necessarily mean faster code. In fact, in many cases, adding additional instructions can make your program execute faster. If you are trying to optimize a particular chunk of code, I encourage you to ask a question about it either here or on Code Review (we need more assembly language questions there!).

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574