### Author Topic: Writing assembly program to do simple arithmetic operations.  (Read 10562 times)

#### amrak

• Jr. Member
• Posts: 3
##### Writing assembly program to do simple arithmetic operations.
« on: May 24, 2016, 11:55:23 AM »
I have started to learn assembly programming in NASM, I want to write a basic arithmetic program. where
1:  the user enters the first digit
2:  then the second digit,
3:  then the program gives the option to choose 1=ADD 2=SUB etc...
4: the results get displayed
The code is given below.
Code: [Select]
`SYS_EXIT equ 1SYS_READ equ 3SYS_WRITE equ 4STDIN equ 0STDOUT equ 1segment .data msg1 db "Enter the first digit", 0xA,0xD len1 equ \$- msg1 msg2 db "Please enter a second digit", 0xA,0xD len2 equ \$- msg2 msg3 db "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ", 0xA,0xD len3 equ \$- msg3 msg4 db "The sum is: " len4 equ \$- msg4 segment .bss choice resb 1  num1 resb 2 num2 resb 2 res resb 1 section .text global _start_start: ;tell linker entry point        mov eax, SYS_WRITE   ; prompt for the first digit        mov ebx, STDOUT        mov ecx, msg1        mov edx, len1        int 0x80 mov eax, SYS_READ    ; accept the first digit mov ebx, STDIN mov ecx, num1 mov edx, 2 int 0x80         mov eax, SYS_WRITE   ; prompt to ask for the second digit        mov ebx, STDOUT        mov ecx, msg2        mov edx, len2         int 0x80 mov eax, SYS_READ   ;accept the second digit mov ebx, STDIN mov ecx, num2 mov edx, 2 int 0x80  mov eax, SYS_WRITE  ; prompt to choose to ADD, SUB, DIV or MUL        mov ebx, STDOUT        mov ecx, msg3        mov edx, len3         int 0x80 mov eax, SYS_READ  ; accept the user choice mov ebx, STDIN mov ecx, choice mov edx, 1 cmp ecx, 1              je _add       ; [glow=red,2,300]can I add je _mul, je _div to branch to other operations?[/glow] int 80h _disp:         mov eax, SYS_WRITE         mov ebx, STDOUT         mov ecx, msg4         mov edx, len4 jmp exit         int 0x80  _add: mov eax, [num1] ; moving the first number to eax register and second number to ebx sub eax, '0' ; and subtracting ascii '0' to convert it into a decimal number mov ebx, [num2] sub ebx, '0' add eax, ebx ; add eax and ebx add eax, '0' ; add '0' to to convert the sum from decimal to ASCII  mov [res], eax ; storing the sum in memory location  ; print the sum mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, res mov edx, 1 int 80h        jmp _dispexit: mov eax, SYS_EXIT xor  ebx, ebx int 80h`The problem is when running the program, after I input two numbers and choose 1 (since my code is incomplete and I have to add instructions to SUB, DIV and MUL) the program fails to display the result. Will be grateful if someone could guide me on how to accomplish my task.
« Last Edit: May 24, 2016, 03:09:53 PM by Frank Kotler »

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: Writing assembly program to do simple arithmetic operations.
« Reply #1 on: May 24, 2016, 04:51:04 PM »
Hi Amrak,
Welcome to the forum!

Code: [Select]
`SYS_EXIT equ 1SYS_READ equ 3SYS_WRITE equ 4STDIN equ 0STDOUT equ 1segment .data msg1 db "Enter the first digit", 0xA,0xD len1 equ \$- msg1 msg2 db "Please enter a second digit", 0xA,0xD len2 equ \$- msg2 msg3 db "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ", 0xA,0xD len3 equ \$- msg3 msg4 db "The sum is: " len4 equ \$- msg4 segment .bss choice resb 1 ; make it 2 ? num1 resb 2 num2 resb 2 res resb 1 section .text global _start_start: ;tell linker entry point        mov eax, SYS_WRITE   ; prompt for the first digit        mov ebx, STDOUT        mov ecx, msg1        mov edx, len1        int 0x80 mov eax, SYS_READ    ; accept the first digit mov ebx, STDIN mov ecx, num1 mov edx, 2 int 0x80         mov eax, SYS_WRITE   ; prompt to ask for the second digit        mov ebx, STDOUT        mov ecx, msg2        mov edx, len2         int 0x80 mov eax, SYS_READ   ;accept the second digit mov ebx, STDIN mov ecx, num2 mov edx, 2 int 0x80  mov eax, SYS_WRITE  ; prompt to choose to ADD, SUB, DIV or MUL        mov ebx, STDOUT        mov ecx, msg3        mov edx, len3         int 0x80 mov eax, SYS_READ  ; accept the user choice mov ebx, STDIN mov ecx, choice mov edx, 1        int 80h ; read it before you compare it! :); cmp ecx, 1; "[contents]", and character '1' ; must specify size (since it's not a register)       cmp byte [ecx], '1'              je _add       ; [glow=red,2,300]can I add je _mul, je _div to branch to other operations?[/glow]; int 80h ; too late; yeah, you can do that; what do you want to do if "none of the above"?_disp:         mov eax, SYS_WRITE         mov ebx, STDOUT         mov ecx, msg4         mov edx, len4 jmp exit  ; too soon!         int 0x80  _add: mov eax, [num1] ; moving the first number to eax register and second number to ebx sub eax, '0' ; and subtracting ascii '0' to convert it into a decimal number mov ebx, [num2] sub ebx, '0' add eax, ebx ; add eax and ebx add eax, '0' ; add '0' to to convert the sum from decimal to ASCII  mov [res], eax ; storing the sum in memory location  ; print the sum mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, res mov edx, 1 int 80h        jmp _dispexit: mov eax, SYS_EXIT xor  ebx, ebx int 80h`
You've got some problems here...
Code: [Select]
`mov eax, [anything]`... moves four bytes into eax. Bigger than your variables. Use "movsx" to zero-extend a byte into a four-byte register, or use a one-byte (8 bit) register (al, bl). Even worse when you move four bytes into a smaller variable!

Due to the nature of SYS_READ, you need a byte for the linefeed (0xA) as well as the byte we're interested in. You account for this with the numbers, but not with "choice".

Since you didn't get the "cmp" right for "choice", you were not getting to "_add" at all, which is why it wasn't displaying anything. Fix that, watch the size of your variables and registers, and give it another shot.

Adding two one-digit numbers can easily give a two-digit result, which won't display correctly. It isn't too difficult to read/print integers up to four billion and change (floating point is a real PITA). You may want to do this, rather than be limited to single digit numbers... but get one digit working first...

Best,
Frank

#### amrak

• Jr. Member
• Posts: 3
##### Re: Writing assembly program to do simple arithmetic operations.
« Reply #2 on: May 25, 2016, 06:40:24 PM »
Thank You @Frank Kotler, I did succeed in getting the result to do 1 digit arithmetic operation. I will be grateful if you can guide me on the mistakes with the program
Code: [Select]
`SYS_EXIT equ 1SYS_READ equ 3SYS_WRITE equ 4STDIN equ 0STDOUT equ 1segment .datamsg1 db "Enter the first digit", 0xA,0xDlen1 equ \$- msg1msg2 db "Please enter a second digit", 0xA,0xDlen2 equ \$- msg2msg3 db "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ", 0xA,0xDlen3 equ \$- msg3msg5    db      10,'Invalid Option',10,0len5    equ     \$ - msg5msg6  equ "Operation: ",0 len6 equ \$- msg6msg4 db "The sum is: ",10len4 equ \$- msg4nline   db  10,0lnline equ     \$ - nline segment .bss choice resb 2   num1 resb 2 num2 resb 2 res resb 2 section .text  global _start _start: ;tell linker entry point        mov eax, SYS_WRITE ;"Enter the first digit", 0xA,0xD        mov ebx, STDOUT        mov ecx, msg1        mov edx, len1        int 0x80 mov eax, SYS_READ ; read the 1st Digit entered by the user mov ebx, STDIN mov ecx, num1 mov edx, 2 int 0x80         mov eax, SYS_WRITE ;"Please enter the second digit", 0xA,0xD        mov ebx, STDOUT        mov ecx, msg2        mov edx, len2        int 0x80 mov eax, SYS_READ ; read 2nd user input mov ebx, STDIN mov ecx, num2 mov edx, 2 int 0x80  mov eax, SYS_WRITE ; "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ",        mov ebx, STDOUT        mov ecx, msg3        mov edx, len3        int 0x80 ; Print on screen the message 8: operation mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, msg6 mov edx, len6 int 80h   ; We get the option selected: any one from 1,2,3,4 mov ebx,STDIN mov ecx,choice mov edx,2 mov eax, SYS_READ int 80h   mov ah, [choice] ; move the users choice into ah register sub ah,'0' cmp ah, 1 ; compare user choice with the available options je _ADD ;if choice == 1 jump to add label cmp ah, 2 je _SUB cmp ah, 3 je _MUL cmp ah, 4 je _DIV          mov eax, SYS_WRITE ; if the wrong choice is entered         mov ebx, STDOUT         mov ecx, msg5         mov edx, len5         int 0x80 jmp exit_printMsg4: mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, msg4 mov edx, len4 int80h jmp _printSum ; print the sum _printSum: mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, res  ; print the value of sum on the screen mov edx, 2  int 0x80 jmp exit   ; jump to exit the program ; moving the first number to eax register and second number to ebx; and subtracting ascii '0' to convert it into a decimal number_ADD: mov al, [num1] sub al, '0' mov bl, [num2] sub bl, '0' add al, bl ; al and bl add al, '0' ; add '0' to to convert the sum from decimal to ASCII  mov [res], al ; storing the sum in memory location int 80h jmp _printMsg4_SUB: mov al, [num1] sub al, '0' mov bl, [num2] sub bl, '0' sub] al, bl ; al and bl add al, '0' ; add '0' to to convert the sum from decimal to ASCII  mov [res], al ; storing the sum in memory location int 80h jmp _printMsg4_DIV:  ; We store the numbers in registers ax and bx mov ax, [num1] sub ax, '0'   ; Convert from ascii to decimall mov bx, [num2] sub bx, '0' mov edx, 0  ;remainder mov eax, 0  ;quotient ; Division. Ax = AX / BX div bx    ; Conversion from decimal to ascii add ax, '0' ; We move the result mov [result], eax int 80h jmp _printMsg4 _MUL:   ; 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 [res], ax int 80h jmp _printMsg4exit: mov eax, SYS_WRITE    mov ebx, STDOUT    mov ecx, nline    mov edx, lnline    int 80h mov eax, SYS_EXIT mov ebx,0 int 80h`
« Last Edit: May 26, 2016, 12:25:11 AM by Frank Kotler »

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: Writing assembly program to do simple arithmetic operations.
« Reply #3 on: May 26, 2016, 03:15:02 AM »
In the first place, I should have mentioned "code tags". Just put the word "code" in square brackets at the beginning of your code and "/code" at the end. (you tried this with "glow", but that doesn't work here) This may or may not make it easier to read, definitely makes it easier to cut and paste.

It does not assemble as posted. Simple typos, mostly. I've got it so it assembles, I think, but I may need a nap or two before I'm done with it. I'll get back to ya. (looks like using ax is not helpful...)

Best,
Frank

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: Writing assembly program to do simple arithmetic operations.
« Reply #4 on: May 26, 2016, 05:36:25 PM »
Okay... One thing I didn't notice at first which caused me quite a bit of trouble: your choice message says 3 is div and 4 is mul, but the code jumped to _mul on 3 and _div on 4. The user (me) is carefully selecting inputs that will give a single-digit result, and it isn't working right. Duh!

Well, I think I've got it working for single digits (and positive, in the case of "sub"). I changed the code to match the message - probably would be better to change the message(?). This is what I've got, at present:
Code: [Select]
`SYS_EXIT equ 1SYS_READ equ 3SYS_WRITE equ 4STDIN equ 0STDOUT equ 1segment .datamsg1 db "Enter the first digit", 0xA,0xDlen1 equ \$- msg1msg2 db "Please enter a second digit", 0xA,0xDlen2 equ \$- msg2msg3 db "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ", 0xA,0xDlen3 equ \$- msg3msg5    db      10,'Invalid Option',10,0len5    equ     \$ - msg5msg6  db "Operation: ",0 len6 equ     \$ - msg6msg4 db "The sum is: ",10len4 equ \$- msg4nline   db  10,0lnline equ     \$ - nline segment .bss choice resb 2   num1 resb 2 num2 resb 2 res resb 2 section .text  global _start _start: ;tell linker entry point        mov eax, SYS_WRITE ;"Enter the first digit", 0xA,0xD        mov ebx, STDOUT        mov ecx, msg1        mov edx, len1        int 0x80 mov eax, SYS_READ ; read the 1st Digit entered by the user mov ebx, STDIN mov ecx, num1 mov edx, 2 int 0x80         mov eax, SYS_WRITE ;"Please enter the second digit", 0xA,0xD        mov ebx, STDOUT        mov ecx, msg2        mov edx, len2        int 0x80 mov eax, SYS_READ ; read 2nd user input mov ebx, STDIN mov ecx, num2 mov edx, 2 int 0x80  mov eax, SYS_WRITE ; "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ",        mov ebx, STDOUT        mov ecx, msg3        mov edx, len3        int 0x80 ; Print on screen the message 8: operation mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, msg6 mov edx, len6 int 80h   ; We get the option selected: any one from 1,2,3,4 mov ebx,STDIN mov ecx,choice mov edx,2 mov eax, SYS_READ int 80h   mov ah, [choice] ; move the users choice into ah register sub ah,'0' cmp ah, 1 ; compare user choice with the available options je _ADD ;if choice == 1 jump to add label cmp ah, 2 je _SUB cmp ah, 4 je _MUL cmp ah, 3 je _DIV          mov eax, SYS_WRITE ; if the wrong choice is entered         mov ebx, STDOUT         mov ecx, msg5         mov edx, len5         int 0x80 jmp exit_printMsg4: mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, msg4 mov edx, len4 int 80h jmp _printSum ; print the sum _printSum: mov eax, SYS_WRITE mov ebx, STDOUT mov ecx, res  ; print the value of sum on the screen mov edx, 2  int 0x80 jmp exit   ; jump to exit the program ; moving the first number to eax register and second number to ebx; and subtracting ascii '0' to convert it into a decimal number_ADD: mov al, [num1] sub al, '0' mov bl, [num2] sub bl, '0' add al, bl ; al and bl add al, '0' ; add '0' to to convert the sum from decimal to ASCII  mov [res], al ; storing the sum in memory location int 80h jmp _printMsg4_SUB: mov al, [num1] sub al, '0' mov bl, [num2] sub bl, '0' sub al, bl ; al and bl add al, '0' ; add '0' to to convert the sum from decimal to ASCII  mov [res], al ; storing the sum in memory location int 80h jmp _printMsg4_DIV:  ; We store the numbers in registers ax and bx mov al, [num1] sub al, '0'   ; Convert from ascii to decimall mov bl, [num2] sub bl, '0' mov ah, 0  ;remainder; mov eax, 0  ;quotient ; Division. Ax = AX / BX div bl    ; Conversion from decimal to ascii add al, '0' ; We move the result mov [res], al; int 80h jmp _printMsg4 _MUL:   ; 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 al, '0'    ; We move the result mov [res], al; int 80h jmp _printMsg4exit: mov eax, SYS_WRITE    mov ebx, STDOUT    mov ecx, nline    mov edx, lnline    int 80h mov eax, SYS_EXIT mov ebx,0 int 80h`
If I get to it, I'll post a version that will handle multiple digits (positive and negative?). Maybe I'll go through it and pick a few nits - stuff that's not exactly an "error", but not really right - carriage returns, for example...

Later,
Frank

#### amrak

• Jr. Member
• Posts: 3
##### Re: Writing assembly program to do simple arithmetic operations.
« Reply #5 on: May 27, 2016, 05:11:41 PM »
Thank you for your time and effort. The mistake in mismatch of the options provided to the users was very stupid of me. Thank you @Frank Kotler