1

I am completely new to the assembly and I have some question about registers still after searching through. currently I'm trying to divide a value over and over again by doing:

1.divide ax over bl (seems that remainder goes to ah, quotient goes to al)

2.move al(quotient) to ax

3.jump to 5 if ax is less or equal to 0

4.jump to 1

5.end

The problem occurs on instruction 2, as i'm trying to move 8 bit value into 16 bit value. Anybody have idea on how to solve the problem?

I am using emu8086 so the register has only x, h and l.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Kenta Nomoto
  • 839
  • 6
  • 11
  • https://stackoverflow.com/a/33959900/2970947 – Elliott Frisch Mar 20 '18 at 04:45
  • As you mention in step 3 "ax is less or equal to 0", maybe you did want to use signed integers everywhere? Then you have to use `idiv` for division, and [`cbw`](http://www.felixcloutier.com/x86/CBW:CWDE:CDQE.html) is simplest 8086 way to sign-extend `al` into `ax`, this is old 8086 instruction, available in emu8086 - while `movzx/movsx` are 80386 instructions, so when writing modern x86 asm code, you would rather want to use `movsx [e/r]ax,al` just for consistency with other extensions (when target register is different than `ax`). When unsigned, answers cover that (`and ax,0FFh` is ok). – Ped7g Mar 20 '18 at 09:17

3 Answers3

6

Your question basically boils down to:

How do I move al to ax.

And the answer to that is that you don't move it, it's already there. The 16-bit ax register is made of of the two 8-bit registers ah and al:

  ______________ ax ______________
 /                                \
+-+-+-+-+-+-+-+-+  +-+-+-+-+-+-+-+-+
|f|e|d|c|b|a|9|8|  |7|6|5|4|3|2|1|0| <- individual bits
+-+-+-+-+-+-+-+-+  +-+-+-+-+-+-+-+-+
 \____    _____/    \_____    ____/
       ah                  al

If you want to ensure that the entirety of ax is set to whatever was in al, you just need to clear the ah part, with something like:

and ax, 0ffh

This will clear all but the lowest (rightmost) eight bits, effectively setting the f..8 region to all zeros, and therefore ensuring that ax becomes al.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Thank you for the info! I thought the register had three different parts ax, ah and al! The problem solved too :) – Kenta Nomoto Mar 20 '18 at 05:59
  • On a modern CPU, use `movzx eax, al` for good performance. (or preferably, `movzx ecx, al` or [any register other than the one that contains the source byte](https://stackoverflow.com/a/44193770/224132)). For small code-size, or 8086, use `mov ah, 0` to do the same thing as `and ax, 0xff`, but with only 2 bytes of code instead of 4. ([xor-zeroing](https://stackoverflow.com/questions/33666617/what-is-the-best-way-to-set-a-register-to-zero-in-x86-assembly-xor-mov-or-and) doesn't save any size for byte registers, and only has major advantages for dword registers.) – Peter Cordes Mar 20 '18 at 07:26
  • 1
    Oh, actually `and` is a good suggestion here, because it sets flags based on the quotient, and you want to branch on that anyway. (i.e. `and ax, 0FFh` / `jz and_result_was_zero`) – Peter Cordes Mar 20 '18 at 07:30
2

You have to distinguish between two cases:

Case 1:

al contains an unsigned number (0...255). In this case you have to clear the upper 8 bits of the 16-bit register ax.

As "paxdiablo" wrote in his answer you could use and ax, 0FFh (3 bytes) for this job however the instruction mov ah, 0 (2 bytes) should be more efficient. Both instructions would do the same.

Case 2:

al contains a signed number (-128...127). In this case you have to clear the upper 8 bits of ax if the highest bit of al is clear; otherwise you have to set them.

The cbw instruction (this instruction has no arguments because it will only work with the ax register) will do that job.

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38
1

Generally speaking, you can move a smaller value into a larger location using movsx or movzx. Movsx maintains the sign of the value (so that if you move 0xfe, that becomes 0xfffe) whereas movzx zero-extends the value (so that 0xfe becomes 0x00fe).

However, in your specific case, you don't need to do any moving at all. AL already designates the lower 8 bits of AX. All you need to do is clear the high bits of AX, which you can do in a variety of ways, but and ax, 0xff is probably the simplest.

zneak
  • 134,922
  • 42
  • 253
  • 328