1

I don't know what is the exact definition of overflow in the division. can you explain it first and then instruct it by the below example?

for example my book has written that this piece of code results to overflow. I don't know why??

mov dx,0087h
mov ax,6002h
mov bx,10h
div bx

but this piece of code is correct and doesn't result to overflow:

mov dx,0087h
mov ax,6000h
mov bx,100h
div bx

so why the first result into overflow but second not what is the difference?

jack.math
  • 77
  • 1
  • 6
  • Possible duplicate of [x86 Assembly: Division Floating Point Exception dividing by 11](https://stackoverflow.com/q/43009970) – Peter Cordes Dec 24 '18 at 17:51

2 Answers2

7

The dividend in registers DX and AX is in fact a 32bit number, in your example it is 00876002h.
It will be divided by the divisor BX and the result (quotient) should fit in register AX. The remainder after unsigned division will be put into register DX.

When you try to divide 00876002h by the contents of BX (10h), the result is 87600h and remainder is 2. Now you should see why it triggers an error: quotient 87600h is too big to fit into 16bit register AX.

Divide overflow (alias division by zero) happens when the divisor is too small. Your example will overflow when BX is below DX.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
vitsoft
  • 5,515
  • 1
  • 18
  • 31
2

0x00876002 / 0x10 = 0x87600, so the quotient of DX:AX / BX doesn't fit in AX, thus you get a #DE exception. Intel's instruction reference manual (x86 SDM vol. 2) has detailed descriptions of every instruction, and the entry for div explains this. There's an HTML extract of the div entry here. See the x86 tag wiki for links to Intel's docs, and other stuff.

Dividing by 10h is a right shift by 1 hex digit, but the high-half of the input, DX, has 2 significant hex digits.

x86 Assembly: Division Floating Point Exception dividing by 11 is mostly a duplicate of this, and @rcgldr's answer has code for extended-precision division (e.g. 32-bit / 16-bit producing a 32-bit quotient and 16-bit remainder) using div that works for an arbitrary 16-bit divisor.


In your specific case you're dividing by a power of 2. This is very inefficient with div.

For these power-of-2 divisions, you should use

; input in DX:AX

shrd ax, dx, 4      ; right shift AX, shifting in bits from DX
shr  dx, 4          ; separately right shift DX

; DX:AX = 0008:7600 = 0x87600 = 32-bit quotient

If you want the remainder, it's the low 4 bits of the original AX, which you should get with mov cl, al / and cl, 0Fh.

SHRD only modifies its destination, not the source, so you need that 2nd shr on DX. This makes sense for larger extended-precision shifts: you want to use a chain of SHRD instructions to shift bits into the top of each element in turn, and don't want to shift in zeros.

Or if you can't use 386 instructions like shrd, you can emulate SHRD with a left and right shift and an OR. Original 8086 doesn't have immediate-count shifts either, so you'd need a count in CL.

; 8086-compatible version of 32-bit division by 10h, i.e. right shift by 4.
; input in DX:AX

mov  bx, dx
mov  cl, 16-4
shl  bx, cl       ; bx = the bits shifted across the 16-bit boundary into low half

mov  cl, 4
shr  ax, cl
shr  dx, cl       ; discards the bits shifted out

or   ax, bx       ; replace the 4 zeros at the top of AX with the bits from DX

; quotient in DX:AX

Or if you know that the result won't overflow, like in the divide-by 100h (right shift by 8) case, you can use just one SHRD.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Trivia - 8086 and 80186 will shift up to 255 times and could be used to zero out registers if cl >= 16. For 80286 and later, the shift count is masked with 01fh, still enough to zero out a 16 bit register. For 80386 and later in 32 bit mode, shift count is masked with 01fh and for 64 bit mode, masked with 03fh (not enough to clear a register). – rcgldr Dec 24 '18 at 18:55