8

I am learning about division in assembly language. According to the book I am learning from, the result of the idiv operation is placed in eax and the remainder in edx.

An exercise in the book is to implement number = result % divisor in assembly.

I would have thought this would be equivalent to a normal divide operation except edx would be the result.

This did not work however and edx returned seemingly garbage.

Why? How do you implemented the above pseudo-code in assembly?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Sonny Ordell
  • 334
  • 2
  • 20
  • 59
  • 4
    I would code a tiny C function, and look at the generated assembly (e.g. with `gcc -O -fverbose-asm -S tiny.c`) – Basile Starynkevitch Nov 22 '11 at 18:33
  • 2
    Your question is similar to http://stackoverflow.com/questions/8021772/assembly-language-how-to-do-modulo/8022107 Show your actual code if you're having specific problems (most likely you're not clearing the upper upper part of rdx:rax, edx:eax or dx:ax). – user786653 Nov 22 '11 at 18:34
  • Hard to guess without seeing code, but one common slip-up is forgetting to zero edx before the idiv. – Jerry Coffin Nov 22 '11 at 18:42

1 Answers1

20

Integer modulo can be implemented in two ways:

Firstly by using DIV or IDIV, where the remainder will be put into EDX, but you need to zero EDX first, or to quote intel:

Operand Size -----------| Dividend | Divisor | Quotient | Remainder
Quadword/doubleword     | EDX:EAX  |  r/m32  |   EAX    |   EDX. 

eg:

eax = eax % 9

when unsigned becomes:

XOR EDX,EDX ;clear the destinations for outputs. this stops the garbage remainder  
MOV ECX,9
DIV ECX
MOV EAX,EDX

when signed, it is:

MOV ECX,9
CDQ ;this will clear EDX due to the sign extension
IDIV ECX
MOV EAX,EDX

The second way is an optimization used when you modulo using a power of two, in this case you AND by one less than the power of two, eg: eax = eax % 8 becomes AND EAX,7.

qwr
  • 9,525
  • 5
  • 58
  • 102
Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • Since idiv is the signed version, shouldn't you CDQ into edx? – harold Nov 22 '11 at 19:03
  • I tried to delete my question but you had already answered. I just want to note that it may change a fair bit after I add a code example. – Sonny Ordell Nov 22 '11 at 19:06
  • @harold: lemme just make signed/unsigned examples, gonna make stuff way clearer – Necrolis Nov 22 '11 at 19:51
  • who the hell down voted this and why? either you don't know x86 assembly or you are down voting for **no reason**.... – Necrolis Nov 23 '11 at 15:09
  • 2
    @Necrolis This doesn't work for signed numbers. I get negative results. which shouldn't be right. – iordanis Nov 26 '13 at 03:16
  • @μακακας It shouldn't be right, but it is. The hardware doesn't perform proper signed division; it performs truncated division which can produce negative remainders. – Michael Morris Nov 30 '13 at 10:16
  • @MichaelMorris: it's not a coincidence that `idiv` semantics exactly match C99 semantics for signed division, which requires that `(a/b) * b + a%b == a`. (https://godbolt.org/g/AQopmc in case anyone wants to play with the outputs for constant inputs) (C89 left some wiggle room for implementations, but CPU vendors in general seem to have agreed on this behaviour for signed division.) You're not alone in disliking it, though, and it means that signed division by powers of 2 needs a fixup after arithmetic right shift (which does do truncating division). And that `AND` isn't C signed modulo. – Peter Cordes Jun 06 '18 at 05:28
  • @Necrolis: there is of course a 3rd way, which compilers actually use for non-power-of-2 inputs: a multiplicative inverse. [Why does GCC use multiplication by a strange number in implementing integer division?](https://stackoverflow.com/q/41183935). Anyway, IDK whether some programming language set the standard for signed division and CPU vendors followed, or if it went the other way around. – Peter Cordes Jun 06 '18 at 05:30
  • @SonnyOrdell - For signed division the IDIV instruction returns a remainder of zero or of the same sign as the dividend. For a proper arithmetic type modulo where the modulo is zero or has the same sign as the divisor, after IDIV, if the remainder is not zero, then compare the sign bits, if they are not the same, add the divisor to the remainder, and increment the quotient (if you need a corresponding quotient), This will result in a signed divide that "rounds" towards negative infinity, instead of one that "rounds" towards zero. – rcgldr Jan 13 '19 at 22:17