0

I'm programming in assembly, and I'm very new to the language. I'm using yasm in Ubuntu to do my programming. I'm supposed to take input from the user and tell whether their input is even or odd. If the input is odd, I need to see if it's greater than 5 or less than 5. Then, after everything, I need to make sure the user wants to go again. I'm pretty sure I have that down, I'm just having trouble verifying the user input. I'm trying to make sure they input a number from 0 to 9.

Below is everything I've written for my program, and I can't find where I'm going wrong. When I try to run it I get this error: Floating point exception (core dumped)

; Data section, declaring variables
section .data
    output  dd  'Enter a single digit between 0 and 9'  ;1st output
    nl  db  0x0a                    
    opLen   equ $-output                                ;length of 1st output
    
    Go  equ 0x59                                        ;to check confirmation
    go  equ 0x79                                        ;to check confirmation
    
    rem dd  0xffff                                      ;empty remainder for modulo
    output1 dd  'You entered an even number'            ;output for even
    op1Len  equ $-output1                               ;even output length
    output2 dd  'You entered an odd number <= 5'        ;output for odd less or equal to 5
    op2Len  equ $-output2                               ;output length for first odd
    output3 dd  'you entered an odd number > 5'         ;output for odd more than 5
    op3Len  equ $-output3                               ;output length for second odd
    output4 dd  '...what?...'                           ;output for if the thing entered is not a number
    op4Len  equ $-output4                               ;else output length
    
    confirm dd  'go again? (y/n): '         ;confirmation message
    cLen    equ $-confirm                   ;confirmation message length
    
    divs    dd  2

section .bss
    input   dd  0xffff                      ;for user input
    again   dd  0xffff                      ;for second user input

section .text
global _start
_start: 
    call printOutput    ;prints first output
    call getInput       ;receives user input
    call checkNumZero   ;checks if number is greater than zero
    call checkEvenOdd   ;does the modulo operation on the number
    cmp dword [rem], 0  ;compares the remainder and 0
    je handleTrueEven   ;if remainder is zero, then the first message is outputted
    call isOdd          ;if the remainder isn't zero, it checks if it is greater or less than 5
    call goAgain        ;asks the user if they want to go again
    

printOutput:
    mov rax, 1
    mov rdi, 1
    mov rsi, output
    mov rdx, opLen
    syscall
    ret

getInput:
    mov rax, 0
    mov rdi, 0
    mov rsi, input
    mov rdx, 0xffff
    syscall
    ret

checkNumZero:
    cmp dword [input], '0'
    jbe checkNumNine
    call else

checkNumNine:
    cmp dword [input], '9'
    ja else
    ret

else:
    mov rax, 1
    mov rdi, 1
    mov rsi, output4
    mov rdx, op4Len
    syscall
    ret

checkEvenOdd:
    mov rax, 0
    mov eax, dword [input]
    div dword [divs]
    mov dword [rem], edx
    ret

handleTrueEven:
    mov rax, 1
    mov rdi, 1
    mov rsi, output1
    mov rdx, op1Len
    syscall
    ret

isOdd:
    cmp dword [input], 5
    jle lessThan
    call moreThan
    ret

lessThan:
    mov rax, 1
    mov rdi, 1
    mov rsi, output2
    mov rdx, op2Len
    syscall
    ret

moreThan:
    mov rax, 1
    mov rdi, 1
    mov rsi, output3
    mov rdx, op3Len
    syscall
    ret

goAgain:
    mov rax, 1
    mov rdi, 1
    mov rsi, confirm
    mov rdx, cLen
    syscall
    
    mov rax, 0
    mov rdi, 0
    mov rsi, again
    mov rdx, 0xffff
    syscall
    
    cmp dword [again], 0x79
    jne doneIf
    cmp dword [again], 0x59
    jne doneIf
    ret

doneIf:
    mov rax, 60
    mov rdi, 0
    syscall
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Kyle Roberts
  • 9
  • 1
  • 6
  • Read the description of `div` carefully. You probably want to zero out `edx` before using it. – Nate Eldredge Feb 12 '21 at 00:50
  • @NateEldredge I don't think my program even reaches `checkEvenOdd` before it terminates. When I run the debugger, it doesn't get past `checkNumZero` and `checkNumNine` – Kyle Roberts Feb 12 '21 at 00:54
  • I would check that again. "Floating point exception" is normally only caused by either floating point instructions, which your program doesn't have any of, and integer divide overflow, which it has exactly one... – Nate Eldredge Feb 12 '21 at 00:55
  • Anyhow a dramatically more efficient way to check even vs odd is `test dword [input], 1 ; jz handleTrueEven`. – Nate Eldredge Feb 12 '21 at 00:56
  • Btw, when I test your code, the fault is precisely at the `div` instruction. (Your debugger can show you that.) – Nate Eldredge Feb 12 '21 at 01:19
  • Some other bugs: the normal way to assemble a string is `output1 db "foo foo foo"`; a string is made of bytes, not dwords. And you can't initialize objects in the `.bss` section; the assembler gives a warning. It looks like your `input dd 0xffff` should be `input resb 0xffff`. As it stands you are reserving only one dword (4 bytes), not `0xffff` bytes, and you are trying to initialize that single dword with the value `0xffff` which is impossible. – Nate Eldredge Feb 12 '21 at 01:21
  • And `cmp dword [input], '0'` should be `cmp byte ...` since after all `'0'` is just one byte and you don't want to compare the three following bytes. It looks like you need to think more carefully about operand sizes as you code. – Nate Eldredge Feb 12 '21 at 01:23
  • @NateEldredge That was actually super helpful! I've changed much of what you suggested. I will keep in mind the values of my variables thank you so much! Now I'm having an issue with the goAgain function. I'll edit what I did to change everything in my original post. – Kyle Roberts Feb 12 '21 at 01:41
  • @NateEldredge never mind, I totally figured it out. Thank you so much for helping me! I learned a lot – Kyle Roberts Feb 12 '21 at 01:59
  • @PeterO. I can't accept my answer until two days from now, so it won't be marked off until then – Kyle Roberts Feb 12 '21 at 02:18

1 Answers1

0

There were several changes made to make this problem correct, which are shown below.

section .data
    output  dd  'Enter a single digit between 0 and 9'  ;1st output
    nl  db  0x0a                    
    opLen   equ $-output                ;length of 1st output
    
    rem dd  0xffff                  ;empty remainder for modulo
    output1 dd  'You entered an even number'        ;output for even
    nl1     db  0x0a
    op1Len  equ $-output1               ;even output length
    output2 dd  'You entered an odd number <= 5'    ;output for odd less or equal to 5
    nl2 db  0x0a
    op2Len  equ $-output2               ;output length for first odd
    output3 dd  'you entered an odd number > 5'     ;output for odd more than 5
    nl3     db  0x0a
    op3Len  equ $-output3               ;output length for second odd
    output4 dd  '...what?...'               ;output for if the thing entered is not a number
    nl4     db  0x0a
    op4Len  equ $-output4               ;else output length
    
    confirm dd  'go again? (y/n):'          ;confirmation message
    nl5     db  0x0a
    cLen    equ $-confirm               ;confirmation message length
    
    divs    db  2

section .bss
    input   resb    0xff                    ;for user input
    again   resb    0xff                    ;for second user input

section .text
global _start
_start: 
    call printOutput    ;prints first output
    call getInput       ;receives user input
    call checkNumZero   ;checks if number is greater than zero
    call checkEvenOdd   ;does the modulo operation on the number
    cmp byte [rem], 0       ;compares the remainder and 0
    je handleTrueEven   ;if remainder is zero, then the first message is outputted
    call isOdd      ;if the remainder isn't zero, it checks if it is greater or less than 5
    ;call goAgain       asks the user if they want to go again
    

printOutput:
    mov rax, 1
    mov rdi, 1
    mov rsi, output
    mov rdx, opLen
    syscall
    ret

getInput:
    mov rax, 0
    mov rdi, 0
    mov rsi, input
    mov rdx, 0xff
    syscall
    ret

checkNumZero:
    cmp byte [input], 0x30
        jae checkNumNine
        call else

checkNumNine:
        cmp byte [input], 0x39
        ja else
    ret

else:
    mov rax, 1
    mov rdi, 1
    mov rsi, output4
    mov rdx, op4Len
    syscall
    call goAgain

checkEvenOdd:
    mov al, byte [input]
    mov ah, 0
    div byte [divs]
    mov byte [rem], ah
    ret

handleTrueEven:
    mov rax, 1
    mov rdi, 1
    mov rsi, output1
    mov rdx, op1Len
    syscall
    call goAgain

isOdd:
    cmp byte [input], '5'
    jbe lessThan
    call moreThan
    call goAgain

lessThan:
    mov rax, 1
    mov rdi, 1
    mov rsi, output2
    mov rdx, op2Len
    syscall
    call goAgain

moreThan:
    mov rax, 1
    mov rdi, 1
    mov rsi, output3
    mov rdx, op3Len
    syscall
    ret

goAgain:
    mov rax, 1
    mov rdi, 1
    mov rsi, confirm
    mov rdx, cLen
    syscall
    
    mov rax, 0
    mov rdi, 0
    mov rsi, again
    mov rdx, 0xff
    syscall
    
    cmp byte [again], 0x79
    je _start
    cmp byte [again], 0x59
    je _start
    jmp doneIf

doneIf:
    mov rax, 60
    mov rdi, 0
    syscall
Kyle Roberts
  • 9
  • 1
  • 6