assemblygdbx86sigfpe

fpu ia-32, floating point exception


I'm learning ia-32 and everything was going fine on 32bit Ubuntu, but I switched to 64bit and started using the flag -m32 and now i can't use DIV anywhere, no matter the content of the registers, it gives me always Floating Point Exception... And I'm sure I'm not dividing by zero. I'm using gcc and gdb.

This is the closest question to my problem: FPU IA-32 SIGFPE, Arithmetic exception

I tried to put the instructions fldcw with 0x220 but makes no difference.

My source code:

.section .text 

Division:
    .int 0x220

str: 
    .asciz "%d"

.global binario             # void binario(int)

binario:
    pushl %ebp          # prologo
    movl %esp,%ebp          # 

    finit
    fldcw Division

    pushl %ebx
    pushl %ecx
    pushl %edx

    movl 8(%ebp),%eax       # param x to eax

    cmpl $0,%eax            # compare x with 0
    je fim              # return recursive call

    movl $2,%ecx            # prepare division
    divl %ecx           # divide eax with 2

    movl $0,%ecx            # clean ecx
    movb %al,%cl            # put division result on cl

    pushl %ecx          # push x/2
    call binario            # recursive call
    add $8,%esp         # clean esp

    movl $0,%ecx            # clean ecx
    movb %ah,%cl            # put division rest on cl

    pushl %ecx          # push division rest
    pushl $str          # push string
    call printf         # call printf function
    addl $8,%esp            # clean esp

fim:

    pushl %edx
    pushl %ecx
    pushl %ebx

    movl %ebp,%esp          # epilogo
    popl %ebp               #
    ret 

GDB log:

28      divl %ecx           # divide eax with 2
2: $ecx = 2
1: $eax = 33
(gdb) 

Program received signal SIGFPE, Arithmetic exception.
binario () at ex08.s:28
28      divl %ecx           # divide eax with 2
2: $ecx = 2
1: $eax = 33

Solution

  • +1 for searching SO and using a debugger, -1 for not reading the instruction set reference ;)

    The div r/m32 variant that you are using divides the 64 bit quantity formed from edx (top 32 bits) and eax (low 32 bits). Furthermore, you also get this exception if your result is out of range. The problem is you are not zeroing edx so it has some random value which causes the whole division to overflow. You need to clear edx (zero-extend eax) before unsigned division, and sign-extend eax into edx before signed division.

    PS: I hope you are not really using div to divide by 2. To divide or multiply by powers of 2 you should use shifts.