NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: amrak 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.
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .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 _disp
exit:
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.
-
Hi Amrak,
Welcome to the forum!
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .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 _disp
exit:
mov eax, SYS_EXIT
xor ebx, ebx
int 80h
You've got some problems here...
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
-
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
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .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
msg5 db 10,'Invalid Option',10,0
len5 equ $ - msg5
msg6 equ "Operation: ",0
len6 equ $- msg6
msg4 db "The sum is: ",10
len4 equ $- msg4
nline db 10,0
lnline 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 _printMsg4
exit:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, nline
mov edx, lnline
int 80h
mov eax, SYS_EXIT
mov ebx,0
int 80h
-
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
-
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:
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .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
msg5 db 10,'Invalid Option',10,0
len5 equ $ - msg5
msg6 db "Operation: ",0
len6 equ $ - msg6
msg4 db "The sum is: ",10
len4 equ $- msg4
nline db 10,0
lnline 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 _printMsg4
exit:
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
-
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