Division in x86 Assembly GAS

mmoe picture mmoe · Sep 23, 2016 · Viewed 11.6k times · Source

Im not quite sure yet how division works in x86 assembly (GAS AT&T syntax). What i wanna do is to divide two longs, and then multiply the quotient with the divisor to see if the new number is equal to the initial number (n/m * m = n).

movl %ebx, %eax
movl %ecx, %edx
idivl %edx
imull %ebx, %edx

cmp %edx, %ebx
je .equal

The code above is a snippet where i do the division. ebx and ecx are two counters that i want to divide, is it correct that the eax register is used as divisor? so when i write idivl %edx i am dividing edx with eax, and i get the integer closest 0? Like 7/2 = 3? I read one place that the quotient is stored in the edx register and the remainder in the ah register, but i was also told that the quotient is stored in the eax register and the remainder in the edx register, which has gotten me confused.

Though the main question here is: i want to divide the value of the ebx register with the value of the ecx register, how should i proceed?

Thanks!

EDIT: the code above yields an floating point exception

Answer

Johan picture Johan · Sep 23, 2016

The idiv instruction takes 2 arguments in 3 registers.
The first implicit argument is the dividend, a 64-bit argument in edx:eax
The low 32 bits are in eax, the high 32 bits are in edx.
The second explicit argument is the divisor, a 32 bit argument in a single register.
For obvious reasons the divisor should not be edx or eax.
The result is returned in eax = Quotient, edx = Remainder.

Knowing this the proper setup should be:

Intel syntax                    pdp-11 syntax
--------------------------------------------------------
.intel_syntax noprefix
mov ebx, dividend
mov ecx, divisor

mov eax,ebx                     movl %ebx, %eax     
cdq                             cdq                 //edx:eax = 32 bit dividend 
idiv ecx                        idivl %ecx          //divide edx:eax by ecx
imul eax, ecx                   imull %ecx, %eax    //multiply result by dividend
cmp ebx, eax                    cmpl %eax, %ebx
je .equal                       je .equal
add eax,edx                     addl %edx, %eax     //add remainder
cmp ebx,eax                     cmpl %eax,%ebx      //should be equal now
je .equal2                      je .equal2

You should keep in mind that div/idiv performs an integer divide!
The result is always an integer with a remainder (which may be zero).

It does not do any floating point. It only generates an exception if the result is too large to fit in 32 bits or if you're dividing by zero, in which case you get a #DE Division error.
The reason you are getting an integer division error is that you are mistakenly using edx as the divisor and because your dividend is 32-bit the higher 32 bits (stored in edx) are always zero and thus you have a division by zero.
Never use the same registers for dividend and divisor!
You'll get this same error if the edx:eax idiv ecx does not fit in 32 bits (i.e. if edx:eax is too large relative to ecx).

See: http://www.felixcloutier.com/x86/IDIV.html and http://www.felixcloutier.com/x86/DIV.html

I have a burning hate for ATT aka PDP syntax which is nonsensical and broken.
You can restore sanity and use Intel syntax in Gas by using the .intel_syntax noprefix pseudo instruction.
See: Can I use Intel syntax of x86 assembly with GCC?