Calculator in Assembly Language - Linux x86 & NASM

2019-06-03 21:21发布

问题:

I am making a calculator in assembly language to be executed on an x86 processor.

Basically, my calculator asks the user to enter two numbers and then to indicate which operation (addition, subtraction, multiplication and division) want to do with them.

My calculator adds, subtracts and multiplies correctly but is unable to divide. In making a division, I always get 1 as the result.

Then I leave my application code complete:

section .data

    ; Messages

    msg1        db      10,'-Calculator-',10,0
    lmsg1       equ     $ - msg1

    msg2        db      10,'Number 1: ',0
    lmsg2       equ     $ - msg2

    msg3        db      'Number 2: ',0
    lmsg3       equ     $ - msg3

    msg4        db      10,'1. Add',10,0
    lmsg4       equ     $ - msg4

    msg5        db      '2. Subtract',10,0
    lmsg5       equ     $ - msg5

    msg6        db      '3. Multiply',10,0
    lmsg6       equ     $ - msg6

    msg7        db      '4. Divide',10,0
    lmsg7       equ     $ - msg7

    msg8        db      'Operation: ',0
    lmsg8       equ     $ - msg8

    msg9        db      10,'Result: ',0
    lmsg9       equ     $ - msg9

    msg10       db      10,'Invalid Option',10,0
    lmsg10      equ     $ - msg10

    nlinea      db      10,10,0
    lnlinea     equ     $ - nlinea

section .bss

    ; Spaces reserved for storing the values ​​provided by the user.

    opc         resb    2
    num1        resb    2
    num2        resb    2
    result      resb    2

section .text

    global _start

_start:

    ; Print on screen the message 1
    mov eax, 4
    mov ebx, 1
    mov ecx, msg1
    mov edx, lmsg1
    int 80h

    ; Print on screen the message 2
    mov eax, 4
    mov ebx, 1
    mov ecx, msg2
    mov edx, lmsg2
    int 80h

    ; We get num1 value.
    mov eax, 3
    mov ebx, 0
    mov ecx, num1
    mov edx, 2
    int 80h

    ; Print on screen the message 3
    mov eax, 4
    mov ebx, 1
    mov ecx, msg3
    mov edx, lmsg3
    int 80h

    ; We get num2 value.
    mov eax, 3
    mov ebx, 0
    mov ecx, num2
    mov edx, 2
    int 80h

    ; Print on screen the message 4
    mov eax, 4
    mov ebx, 1
    mov ecx, msg4
    mov edx, lmsg4
    int 80h

    ; Print on screen the message 5
    mov eax, 4
    mov ebx, 1
    mov ecx, msg5
    mov edx, lmsg5
    int 80h

    ; Print on screen the message 6
    mov eax, 4
    mov ebx, 1
    mov ecx, msg6
    mov edx, lmsg6
    int 80h

    ; Print on screen the message 7
    mov eax, 4
    mov ebx, 1
    mov ecx, msg7
    mov edx, lmsg7
    int 80h

    ; Print on screen the message 8
    mov eax, 4
    mov ebx, 1
    mov ecx, msg8
    mov edx, lmsg8
    int 80h

    ; We get the option selected.
    mov ebx,0
    mov ecx,opc
    mov edx,2
    mov eax,3
    int 80h

    mov ah, [opc]   ; Move the selected option to the registry ah
    sub ah, '0'     ; Convert from ascii to decimal

    ; We compare the value entered by the user to know what operation to perform.

    cmp ah, 1
    je add
    cmp ah, 2
    je subtract
    cmp ah, 3
    je multiply
    cmp ah, 4
    je divide

    ; If the value entered by the user does not meet any of the above 
    ; conditions then we show an error message and we close the program.
    mov eax, 4
    mov ebx, 1
    mov ecx, msg10
    mov edx, lmsg10
    int 80h

    jmp exit

add:
    ; We keep the numbers in the registers eax and ebx
    mov eax, [num1]
    mov ebx, [num2]

    ; Convert from ascii to decimal
    sub eax, '0'
    sub ebx, '0'

    ; Add
    add eax, ebx

    ; Conversion from decimal to ascii
    add eax, '0'

    ; We move the result
    mov [result], eax

    ; Print on screen the message 9
    mov eax, 4
    mov ebx, 1
    mov ecx, msg9
    mov edx, lmsg9
    int 80h

    ; Print on screen the result
    mov eax, 4
    mov ebx, 1
    mov ecx, result
    mov edx, 1
    int 80h

    ; We end the program
    jmp exit

subtract:
    ; We keep the numbers in the registers eax and ebx
    mov eax, [num1]
    mov ebx, [num2]

    ; Convert from ascii to decimal
    sub eax, '0'
    sub ebx, '0'

    ; Subtract
    sub eax, ebx

    ; Conversion from decimal to ascii
    add eax, '0'

    ; We move the result
    mov [result], eax

    ; Print on screen the message 9
    mov eax, 4
    mov ebx, 1
    mov ecx, msg9
    mov edx, lmsg9
    int 80h

    ; Print on screen the result
    mov eax, 4
    mov ebx, 1
    mov ecx, result
    mov edx, 1
    int 80h

    ; We end the program
    jmp exit

multiply:

    ; We store the numbers in registers ax and bx
    mov ax, [num1]
    mov bx, [num2]

    ; Convert from ascii to decimal
    sub ax, '0'
    sub bx, '0'

    ; Multiply. AL = AX x BX
    mul bx

    ; Conversion from decimal to ascii
    add al, '0'

    ; We move the result
    mov [result], al

    ; Print on screen the message 9
    mov eax, 4
    mov ebx, 1
    mov ecx, msg9
    mov edx, lmsg9
    int 80h

    ; Print on screen the result
    mov eax, 4
    mov ebx, 1
    mov ecx, result
    mov edx, 1
    int 80h

    ; We end the program
    jmp exit

divide:
    ; IN THIS LABEL IS THE ERROR!

    ; We store the numbers in registers ax and bx
    mov dx, 0
    mov ax, [num1]
    mov bx, [num2]

    ; Convert from ascii to decimall
    sub ax, '0'
    sub bx, '0'
    ; Division. AX = DX:AX / BX
    div bx

    ; Conversion from decimal to ascii
    add ax, '0'
    ; We move the result
    mov [result], ax

    ; Print on screen the message 9
    mov eax, 4
    mov ebx, 1
    mov ecx, msg9
    mov edx, lmsg9
    int 80h

    ; Print on screen the result
    ; ALWAYS PRINTS 1
    mov eax, 4
    mov ebx, 1
    mov ecx, result
    mov edx, 1
    int 80h

    ; We end the program
    jmp exit

exit:
    ; Print on screen two new lines
    mov eax, 4
    mov ebx, 1
    mov ecx, nlinea
    mov edx, lnlinea
    int 80h
    ; End the program
    mov eax, 1
    mov ebx, 0
    int 80h

The error must be found inside the tag "divide".

Why do I always get 1 as result of a division?

I hope that someone with more experience can help me with this.


Thank you all very much. My calculator finally works. Here is my final code:

    section .data

    ; Messages

    msg1        db      10,'-Calculator-',10,0
    lmsg1       equ     $ - msg1

    msg2        db      10,'Number 1: ',0
    lmsg2       equ     $ - msg2

    msg3        db      'Number 2: ',0
    lmsg3       equ     $ - msg3

    msg4        db      10,'1. Add',10,0
    lmsg4       equ     $ - msg4

    msg5        db      '2. Subtract',10,0
    lmsg5       equ     $ - msg5

    msg6        db      '3. Multiply',10,0
    lmsg6       equ     $ - msg6

    msg7        db      '4. Divide',10,0
    lmsg7       equ     $ - msg7

    msg8        db      'Operation: ',0
    lmsg8       equ     $ - msg8

    msg9        db      10,'Result: ',0
    lmsg9       equ     $ - msg9

    msg10       db      10,'Invalid Option',10,0
    lmsg10      equ     $ - msg10

    nlinea      db      10,10,0
    lnlinea     equ     $ - nlinea

section .bss

    ; Spaces reserved for storing the values ​​provided by the user.

    opc:        resb    2
    num1:       resb    2
    num2:       resb    2
    result:     resb    2

section .text

    global _start

_start:

    ; Print on screen the message 1
    mov eax, 4
    mov ebx, 1
    mov ecx, msg1
    mov edx, lmsg1
    int 80h

    ; Print on screen the message 2
    mov eax, 4
    mov ebx, 1
    mov ecx, msg2
    mov edx, lmsg2
    int 80h

    ; We get num1 value.
    mov eax, 3
    mov ebx, 0
    mov ecx, num1
    mov edx, 2
    int 80h

    ; Print on screen the message 3
    mov eax, 4
    mov ebx, 1
    mov ecx, msg3
    mov edx, lmsg3
    int 80h

    ; We get num2 value.
    mov eax, 3
    mov ebx, 0
    mov ecx, num2
    mov edx, 2
    int 80h

    ; Print on screen the message 4
    mov eax, 4
    mov ebx, 1
    mov ecx, msg4
    mov edx, lmsg4
    int 80h

    ; Print on screen the message 5
    mov eax, 4
    mov ebx, 1
    mov ecx, msg5
    mov edx, lmsg5
    int 80h

    ; Print on screen the message 6
    mov eax, 4
    mov ebx, 1
    mov ecx, msg6
    mov edx, lmsg6
    int 80h

    ; Print on screen the message 7
    mov eax, 4
    mov ebx, 1
    mov ecx, msg7
    mov edx, lmsg7
    int 80h

    ; Print on screen the message 8
    mov eax, 4
    mov ebx, 1
    mov ecx, msg8
    mov edx, lmsg8
    int 80h

    ; We get the option selected.
    mov ebx,0
    mov ecx,opc
    mov edx,2
    mov eax,3
    int 80h

    mov ah, [opc]       ; Move the selected option to the registry ah
    sub ah, '0'     ; Convert from ascii to decimal

    ; We compare the value entered by the user to know what operation to perform.

    cmp ah, 1
    je add
    cmp ah, 2
    je subtract
    cmp ah, 3
    je multiply
    cmp ah, 4
    je divide

    ; If the value entered by the user does not meet any of the above
    ; conditions then we show an error message and we close the program.
    mov eax, 4
    mov ebx, 1
    mov ecx, msg10
    mov edx, lmsg10
    int 80h

    jmp exit

add:
    ; We keep the numbers in the registers al and bl
    mov al, [num1]
    mov bl, [num2]

    ; Convert from ascii to decimal
    sub al, '0'
    sub bl, '0'

    ; Add
    add al, bl

    ; Conversion from decimal to ascii
    add al, '0'

    ; We move the result
    mov [result], al

    ; Print on screen the message 9
    mov eax, 4
    mov ebx, 1
    mov ecx, msg9
    mov edx, lmsg9
    int 80h

    ; Print on screen the result
    mov eax, 4
    mov ebx, 1
    mov ecx, result
    mov edx, 2
    int 80h

    ; We end the program
    jmp exit

subtract:
    ; We keep the numbers in the registers al and bl
    mov al, [num1]
    mov bl, [num2]

    ; Convert from ascii to decimal
    sub al, '0'
    sub bl, '0'

    ; Subtract
    sub al, bl

    ; Conversion from decimal to ascii
    add al, '0'

    ; We move the result
    mov [result], al

    ; Print on screen the message 9
    mov eax, 4
    mov ebx, 1
    mov ecx, msg9
    mov edx, lmsg9
    int 80h

    ; Print on screen the result
    mov eax, 4
    mov ebx, 1
    mov ecx, result
    mov edx, 1
    int 80h

    ; We end the program
    jmp exit

multiply:

    ; We store the numbers in registers al and bl
    mov al, [num1]
    mov bl, [num2]

    ; Convert from ascii to decimal
    sub al, '0'
    sub bl, '0'

    ; Multiply. AX = AL x BL
    mul bl

    ; Conversion from decimal to ascii
    add ax, '0'

    ; We move the result
    mov [result], ax

    ; Print on screen the message 9
    mov eax, 4
    mov ebx, 1
    mov ecx, msg9
    mov edx, lmsg9
    int 80h

    ; Print on screen the result
    mov eax, 4
    mov ebx, 1
    mov ecx, result
    mov edx, 1
    int 80h

    ; We end the program
    jmp exit

divide:

    ; We store the numbers in registers ax and bx
    mov al, [num1]
    mov bl, [num2]

    mov dx, 0
    mov ah, 0

    ; Convert from ascii to decimall
    sub al, '0'
    sub bl, '0'

    ; Division. AL = AX / BX
    div bl

    ; Conversion from decimal to ascii
    add ax, '0'
    ; We move the result
    mov [result], ax

    ; Print on screen the message 9
    mov eax, 4
    mov ebx, 1
    mov ecx, msg9
    mov edx, lmsg9
    int 80h

    ; Print on screen the result
    mov eax, 4
    mov ebx, 1
    mov ecx, result
    mov edx, 1
    int 80h

    ; We end the program
    jmp exit

exit:
    ; Print on screen two new lines
    mov eax, 4
    mov ebx, 1
    mov ecx, nlinea
    mov edx, lnlinea
    int 80h
    ; End the program
    mov eax, 1
    mov ebx, 0
    int 80h

回答1:

You're reading two bytes (characters) into num1 and num2 for your number input. This will generally be a single digit (0-9) that you are typing in and a newline character. When you go to do an operation, you read 2 bytes each into ax and bx, so if num1 was 5 and num2 was 1, ax will be 0xa35 and bx will be 0xa31. You then subtract 0x30 from each and divide, giving 1 in all cases, which you then convert to 0x31 '1' and print.

Now in other cases (add/sub), you're actually loading 4 bytes into eax and ebx. So when you add 5 and 1, you'll get 0xa310a35 in eax and 0x????0a31 in ebx (the ???? comes from whatever happened to be in result.) However, after subtracting 0x30 from each and adding, the lowest byte of eax will 0x06, so you'll print 6 as you ignore what is in the upper bytes.