8

I noticed when EDX contains some random default value like 00401000, and I then use a DIV instruction like this:

mov eax,10
mov ebx,5
div ebx

it causes an INTEGER OVERFLOW ERROR. However, if I set edx to 0 and do the same thing it works. I believed that using div would result in the quotient overwriting eax and the remainder overwriting edx.

Getting this INTEGER OVERFLOW ERROR really confuses me.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Kanna Kim
  • 383
  • 1
  • 3
  • 15
  • 3
    That's just how the instruction is defined/implemented - for a 32-bit operand, it divides the 64-bit value in edx:eax with the 32-bit operand value. – 500 - Internal Server Error Jul 16 '16 at 23:39
  • 1
    you are dividing a 64 bit number by a 32 bit number, you have to set all 64 bits before you start otherwise your result will make no sense. – old_timer Jul 17 '16 at 00:13
  • That link is from the [FAQ section of the x86 tag wiki](http://stackoverflow.com/tags/x86/info). There's a ton of good stuff there for people dealing with asm. – Peter Cordes Jul 17 '16 at 02:46
  • 2
    You would be very well served to look at an instruction reference before using an unfamiliar opcode. :) – David Hoelzer Jul 17 '16 at 08:29
  • Related: 8-bit operand size is a special case: `div bl` (16b / 8b => 8b), using AX (not DL:AL). [8086 assembly on DOSBox: Bug with idiv instruction?](https://stackoverflow.com/a/43575674) – Peter Cordes Jun 16 '18 at 12:49
  • A possible canonical duplicate (for other questions, not this) for 8-bit `div` without zeroing AH [Assembly Divide by zero](https://stackoverflow.com/q/38788694) – Peter Cordes Mar 11 '21 at 12:35
  • In what context does it cause "INTEGER OVERFLOW ERROR"? What CPU, external hardware, system, etc.? – Peter Mortensen Dec 30 '22 at 17:51

2 Answers2

22

What to do

For 32-bit / 32-bit => 32-bit division: zero- or sign-extend the 32-bit dividend from EAX into 64-bit EDX:EAX.
For 16-bit, AX into DX:AX with cwd or xor-zeroing.

  • unsigned: XOR EDX,EDX then DIV divisor
  • signed: CDQ then IDIV divisor

See also When and why do we sign extend and use cdq with mul/div?


Why (TL;DR)

For DIV, the registers EDX and EAX form one single 64 bit value (often shown as EDX:EAX), which is then divided, in this case, by EBX.

So if EAX = 10 or hex A and EDX is, say 20 or hex 14, then together they form the 64 bit value hex 14 0000 000A or decimal 85899345930. If this is divided by 5, the result is 17179869186 or hex
4 0000 0002, which is a value that does not fit in 32 bits.

That is why you get an integer overflow.

If, however, EDX were only 1, you would divide hex 1 0000 000A by 5, which results in hex
3333 3335. That is not the value you wanted, but it does not cause an integer overflow.

To really divide 32 bit register EAX by another 32 bit register, take care that the top of the 64 bit value formed by EDX:EAX is 0.

So, before a single division, you should generally set EDX to 0.

(Or for signed division, cdq to sign extend EAX into EDX:EAX before idiv)


But EDX does not have always have to be 0. It can just not be that big that the result causes an overflow.

One example from my BigInteger code:

After a division with DIV, the quotient is in EAX and the remainder is in EDX. To divide something like a BigInteger, which consists of an array of many DWORDS, by 10 (for instance to convert the value to a decimal string), you do something like the following:

    ; ECX contains number of "limbs" (DWORDs) to divide by 10
    XOR     EDX,EDX      ; before start of loop, set EDX to 0
    MOV     EBX,10
    LEA     ESI,[EDI + 4*ECX - 4] ; now points to top element of array
@DivLoop:
    MOV     EAX,[ESI]
    DIV     EBX          ; divide EDX:EAX by EBX. After that,
                         ; quotient in EAX, remainder in EDX
    MOV     [ESI],EAX
    SUB     ESI,4        ; remainder in EDX is re-used as top DWORD... 
    DEC     ECX          ; ... for the next iteration, and is NOT set to 0.
    JNE     @DivLoop

After that loop, the value represented by the entire array (i.e. by the BigInteger) is divided by 10, and EDX contains the remainder of that division.

FWIW, in the assembler I use (Delphi's built-in assembler), labels starting with @ are local to the function, i.e. they don't interfere with equally named labels in other functions.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • This might be a better canonical answer to the "why did my broken divide code not work" FAQ than the duplicate I marked. I made an edit to fix a syntax error, but there's another bug: `ESI` holds a pointer in your loop, so `JNE @DivLoop` won't exit the loop until you've gone down the entire address space to `ESI = (int*)4`. Maybe you meant to use a `dec ecx`, or a `cmp`? – Peter Cordes Jul 18 '16 at 09:56
  • 1
    FWIW, @PeterCordes: in my assembler, both `DIV EAX,EBX` and `DIV EBX`are allowed. But since in one version, `DIV EBX` generated bad code, but `DIV EAX,EBX` didn't, I always use the latter. – Rudy Velthuis Jul 18 '16 at 09:57
  • @PeterCordes: I didn't copy this verbatim (my code uses unrolled loops and is far more complicated). I guess I forgot something. I'll amend. – Rudy Velthuis Jul 18 '16 at 09:58
  • Ah, ok, I was wondering how that `div eax, ebx` got in there in an example based on working code! (and yes, I could tell it must not have been copy/pasted verbatim). While you're at it, I'd suggest a comment to point out that it's intentional that you don't zero `EDX` inside the loop; that the remainder from the previous division is the upper half of the input to the next limb. (That is intentional, right? That seems sensible for BigInteger) – Peter Cordes Jul 18 '16 at 09:59
  • @PeterCordes: I think my comment at the end of the loop alread explains this (i.e. that EDX is not zeroed out). – Rudy Velthuis Jul 18 '16 at 10:03
  • Oh, yes. I was expecting that comment to say something about the looping itself, so didn't read it. BTW, I updated the x86 tag wiki to point here. I'm going to leave this marked as a duplicate for now, though, since I think the link to my answer on the other question is also potentially useful. Thanks for taking the time to write a nice answer to one of these bad questions so we can just link instead of retyping stuff in comments on new dups :) – Peter Cordes Jul 18 '16 at 10:04
2

The DIV instruction divides EDX:EAX by the r/m32 that follows the DIV instruction. So, if you fail to set EDX to zero, the value you are using becomes extremely large.

Trust that helps

quasar66
  • 555
  • 4
  • 14