0

I'm working in assembly 386 and i keep dividing a number by 0Ah in a loop i keep getting a result that i cant understand here is my code:

MOV EAX,94Ch
MOV ten,0Ah;ten is of size DD that i've defined 
XOR ECX,ECX
L1:
CMP EAX,0;check if the number is zero
JE somewhere
DIV ten
INC CL
JMP L1

When there is 17h in EAX and i divide by 0Ah i get CCCF when i supposed to get 2 in EAX. why is it like that?

user3100258
  • 35
  • 1
  • 5

1 Answers1

1

The DIV instruction is a bit tricky, and to understand it, you need to look carefully at the documentation.

First, notice that your code is doing a 32-bit division. The way I know that is you have DIV ten, and ten is a DWORD (since you've declared it with DD). A DWORD is 32 bits.

From the above-linked documentation, we can see that a 32-bit division divides EDX:EAX by the operand (in this case, ten). It stores the quotient in EAX, and the remainder in EDX.

Okay, so wait a minute—what is EDX:EAX? This is a notation for a way to store a 64-bit value using two 32-bit registers. The high DWORD is in EDX, and the low DWORD is in EAX. Combine them together, and you get a 64-bit value.

Hopefully now you see why your solution of zeroing EDX worked, and why you were getting the wrong result without doing it. The division was actually implicitly using the EDX register as part of the dividend, so if it contains garbage, the result of the division will be wrong.

And now that you understand the problem, you can memorize this simple rule: whenever you do a 32-bit division, using the DIV instruction, always pre-zero the EDX register. The idiomatic and most efficient way to zero out a register is, of course, with the XOR instruction.


Note that similar problem occurs with signed division (IDIV), except that, in this case, you don't simply want to zero out EDX. You need to extend the value in EAX in a way that respects the sign bit. The CDQ instruction does this for you: it sign-extends EAX into EDX:EAX, ready for an IDIV. Another simple rule to learn—CDQ should virtually always precede IDIV.


A final bit of free optimization advice:

CMP EAX, 0

is equivalent to:

TEST EAX, EAX

but the latter assembles to fewer bytes of code (because it doesn't use an immediate operand) and is faster in many cases (both because of its smaller size and the fact that it is more likely to macro-fuse with the subsequent branch instruction, e.g. JE).

So another rule (isn't assembly programming fun?): when you are testing to see whether a register is 0, use TEST to bitwise-AND the register with itself.

The only time you would use CMP xxx, 0 is when you want to see if a memory location is 0 (without first loading it into a register).

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