Aakash Anuj
Aakash Anuj

Reputation: 3871

Assembly language program to find the GCD - Floating point exception

With this program, I am intending to find the GCD of two numbers. But the result I get is "Floating point exception(core dumped)". What is the problem? The code I am trying to generate is

int main() {
int sml, lrg, rem;
read %d sml
read %d lrg
while (sml > 0){
rem = lrg % sml;
lrg = sml;
sml = rem;
}
print %d lrg;
return 0;
}

The assembly file generated by me is:

    .file "gcd.c"
    .section .rodata
.LC0:
    .string "%d"
.LC1:
    .string "%d\n"

    .text
    .globl main
    .type main, @function
main:
    pushl %ebp
    movl  %esp, %ebp
    andl  $-16, %esp
    subl  $32, %esp

    leal  -8(%ebp), %eax    #scan a value
    movl  %eax,  4(%esp)
    movl  $.LC0,  (%esp)
    call scanf

    leal  -12(%ebp), %eax   #scan a value
    movl  %eax,  4(%esp)
    movl  $.LC0,  (%esp)
    call scanf


.L2:
    movl $0, %eax
    cmpl -8(%ebp),%eax
    jle .L0
    jmp .L1

.L0:
    movl  -12(%ebp),%eax
    movl -8(%ebp),%ecx
    movl %eax,%edx
    sarl $31, %edx
    idivl %ecx
    movl %edx,%eax
    movl %eax, -16(%ebp)
    movl -8(%ebp),%edx
    movl %edx, -12(%ebp)
    movl -16(%ebp),%edx
    movl %edx, -8(%ebp)
    jmp .L2

.L1:
    movl -12(%ebp), %eax
    movl  %eax,  4(%esp)
    movl $.LC0, (%esp)
    call printf

    movl $0, %edx

    movl $0, %eax       #end of program
    leave
    ret

.LFE2:
    .size     main, .-main 
    .ident     "GCC: (GNU) 4.2.3 (4.2.3-6mnb1)" 
    .section    .note.GNU-stack,"",@progbits

On the other hand, this assembly code works

    .file   "check.c"
    .section    .rodata
.LC0:
    .string "%d"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    leal    20(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $.LC0, (%esp)
    call    scanf
    leal    24(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $.LC0, (%esp)
    call    scanf
    jmp .L2
.L3:
    movl    24(%esp), %eax
    movl    20(%esp), %ecx
    movl    %eax, %edx
    sarl    $31, %edx
    idivl   %ecx
    movl    %edx, 28(%esp)
    movl    20(%esp), %eax
    movl    %eax, 24(%esp)
    movl    28(%esp), %eax
    movl    %eax, 20(%esp)
.L2:
    movl    20(%esp), %eax
    testl   %eax, %eax
    jg  .L3
    movl    24(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    movl    $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits

Upvotes: 0

Views: 1916

Answers (2)

Eric Postpischil
Eric Postpischil

Reputation: 223494

Your comparison and jump are wrong. The working code has:

testl   %eax, %eax
jg  .L3

The broken code has:

movl $0, %eax
cmpl -8(%ebp),%eax
jle .L0
jmp .L1

The former compares %eax (which contains the most recently computed residue) to zero, and it continues the loop (jumps to .L3) if the residue is positive (greater than zero).

The latter compares 0 to -8(%ebp) (the most recently computed residue). Note that the order is different; it compares 0 to -8(%ebp), not -8(%ebp) to 0. The testl instruction compares the value (after performing an AND) with zero. If the value is positive, it is “greater than” zero. The cmpl instruction compares its second operand to its first operand; if the second operand exceeds the first, the result is “greater than”. This is because, in Intel’s manuals and assembly language, instructions are written with their operands in the reverse order. E.g, moving 3 into %eax would be “mov %eax, $3”. However, the assembler you are using reverses all the operands from Intel’s order (due to legacy reasons).

So, the broken code continues the loop (jumps to .L0) if 0 is less than or equal to the residue. Thus, if the residue is zero, the loop continues. You can change the jle to jl:

jl .L0

Alternately, you could eliminate the redundant unconditional jump:

movl $0, %eax
cmpl -8(%ebp),%eax
jge .L1

Also, you probably want to change:

movl $.LC0, (%esp)
call _printf

to:

movl $.LC1, (%esp)
call _printf

so that you pass "%d\n" to printf instead of passing "%d".

Incidentally, the idivl instruction generates a divide error, not a floating-point exception. Your system is misreporting the error.

Upvotes: 2

ouah
ouah

Reputation: 145899

You probably have a division by zero in this line:

idivl %ecx

With a 0 value in ecx register.

Upvotes: 3

Related Questions