I have done my best to explain all of my thought process when adding these two numbers. However, upon running the resulting executable I end up with
"Sum is: j" which is clearly wrong. Additionally, it seems that no matter which inputs I give the sum stays as "j" so there must be something awfully wrong.
I believe this code should work but my understanding is clearly flawed.
Where should I start in fixing this? I just recently began learning assembly.
section .data ;line 1
msg db "Sum is: "
len equ $ - msg
section .bss
num1 resb 1
eol1 resb 1
num2 resb 1
eol2 resb 1
sum resb 2
section .text
global _start
print_int:
mov eax, 4 ;defining routine print_int
mov ebx, 1 ;file descriptor (stdout)
int 0x80 ;system call number (sys_write)
ret ;return back
_start:
;Read and store user input for num1
mov eax, 3
mov ebx, 0
mov ecx, num1
mov edx, 2 ;2 bytes of info
int 80h
mov byte [eol1], 0xA ; value of first end of line
;Read and store user input for num2
mov eax, 3
mov ebx, 0
mov ecx, num2
mov edx, 2 ;2 bytes of info
int 80h
mov byte [eol2], 0xA ;value of 2nd end of line
;Add num1 and num2
mov eax, num1
sub eax, '0' ;this is so that the value in 3 is set to 3 because
;'3' and '0' actually are ASCII values
mov ebx, num2
sub ebx, '0'
add eax, ebx ;Move the sum of 0x3 and 0x4 into eax
add eax, '0' ;Set eax to be the ASCII value for the result of the sum
mov [sum], eax ;Set this ascii value of the sum to sum
mov ecx, msg ;Move msg ('Sum is: ') into eax
mov edx, len ;Move len (length of msh) into edx
call print_int ; call routine print_int above
;load sum to to be printed
mov ecx, sum
mov edx, 2 ;size in bytes of sum
call print_int
mov eax, 1 ;system call number (sys_exit)
xor ebx, ebx
int 0x80 ;line 43
Your program operates on 2 single digit numbers inputted by the user.
mov eax, num1
mov ebx, num2
On NASM, this will move the address of these variables in those registers. What you want is the contents! You need to write the square brackets.
But wait - since the input has only a single byte of information, you should read the data in the byte-sized registers AL and BL.
mov al, [num1]
mov bl, [num2]
All subtractions and additions then will also have to use these smaller sizes.
sub al, '0' ;From character '0'-'9' to number 0-9
sub bl, '0'
add al, bl
add al, '0' ;From number 0-9 to character '0'-'9'
The character in AL is what you want to print. Easiest is to first append the newline 0xA in the AH register and then write AX in the memory.
mov ah, 0xA
mov [sum], ax
All the above is correct whenever the sum of the 2 single digit numbers was less than 10.
Imagine what will happen when you input e.g. numbers 5 and 8 ?
The sum (13) would require 2 characters leaving no room for the extra newline character. The largest sum will come from adding 9 and 9 (18).
Best re-define "sum" as sum resb 3.
Then write the following:
mov al, [num1]
mov bl, [num2]
sub al, '0'
sub bl, '0'
add al, bl
mov edx, 2 ;String length if single digit sum
mov ecx, sum ;Address of sum
cmp al, 10
jb SingleDigit
mov byte [ecx], '1'
inc ecx ;Move to position for the units/newline
inc edx ;String length if double digit sum
sub al, 10 ;Only keep the units
SingleDigit:
add al, '0' ;From number 0-9 to character '0'-'9'
mov ah, 0xA ;Append newline
mov [ecx], ax
mov ecx, sum
call print_int
Related
The code just prints out nothing what would I do for the output that will be 150 and 48? I'm practicing nasm
section .data
num1 db 99
num2 db 51
result db 0
section .text
global _start
_start:
; Addition
mov al, [num1]
add al, [num2]
mov [result], al
call display_result
; Subtraction
mov al, [num1]
sub al, [num2]
mov [result], al
call display_result
; Exit program
mov eax, 1
int 0x80
display_result:
; Display result
mov edx, 1
mov ecx, [result]
mov ebx, 1
mov eax, 4
int 0x80
; Display newline
mov edx, 1
mov ecx, 10
mov ebx, 1
mov eax, 4
int 0x80
exit:
mov eax, 1
int 0x80`
I expect for my coding to print the Addition and Subtraction of Num1 and Num2 but it is not printing what would I do for it to print?
See DIV instruction, I think it will best fit your needs. Just divide number by 10 and add the remainder to ASCII '0' value and your result will be one digit from the back of the number you are trying to print. For example: 157 will produce 7 remainder first time, 5 second time and then you'll be left with 1 itself. Hope you get the idea.
I'm super new to assembly, and I've spent literally hours trying to figure this out. The program I'm making is supposed to take two numbers from zero to nine, then multiply them and show the correct answer (ex: 9 times 3 is 27). I need to have the 2 numbers be input from the user with the notation of "space number space number" (an example could be " 5 3"). I tried making the code without input (hardcode the numbers) and that works, but when I try to make the numbers come from input, the result is wrong. The program is supposed to take two numbers from zero to nine, then multiply them. I really can't figure out what's wrong...Any help at all would be very much appreciated.
When I enter: " 5 3" it outputs "? 4" (it should be 15)
When I enter: " 9 3" it still outputs "? 4" (it should be 27)
When I enter: "5 3" it outputs "?6"
When I enter: "9 3" it outputs "??4"
When I check var1 and var2 (by making it print them after them being read), the numbers are correct. As in, if " 5 3" is entered var1 does print 5 and var2 does print 3. Even if the spaces are changed, var1 and var2 print the correct numbers (so if I enter "5 3" var1 is still 5, and var2 is still 3).
My professor just explained what to do to get input, but I'm not 100% sure how it works. I find it odd that the output is different depending on where the spaces are, as var1 and var2 should both be accepting 2 bytes.
My code that's incorrect:
;this program multiplies two numbers input by the user, being able to solve with two digits
;the notation for the input should be space number space number (ex:" 9 3")
section .data
section .bss
var1 resb 2
var2 resb 2
result resb 2
tensdigit resb 2
onesdigit resb 2
section .text
global _start
_start:
;reads & saves user input for var1
mov eax, 3
mov ebx, 0
mov ecx, var1
mov edx, 2 ;2 bytes of info
int 80h
;reads & saves user input for var2
mov eax, 3
mov ebx, 0
mov ecx, var2
mov edx, 2 ;2 bytes of info
int 80h
mov al, [var1]
; sub al, '0' ;not sure if this is needed or not
mov bl, [var2]
; sub bl, '0'
;multiply bl by al
mul bl
; sub ax, '0'
mov [result], ax
;divide by ten
mov ax, 0 ;set the register to 0! Very important to avoid errors
mov ax, [result]
mov bx, 10
div bx ;divide by ten
mov [tensdigit], al ;this should have 1 if using 12 (2 if 24, etc)
mov ax, [result]
sub ax, 10
mov [result], ax ;move new number into result
mov al, [result]
mov bl, 10
div bl
;find the remainder
mov [onesdigit], ah
add [tensdigit], word '0' ;add 0 to ensure it's considered a number
add [result], word '0'
add [onesdigit], word '0'
;print tensdigit
mov eax, 4
mov ebx, 1
mov ecx, tensdigit
mov edx, 2
int 80h
;print onesdigit
mov eax, 4
mov ebx, 1
mov ecx, onesdigit
mov edx, 2
int 80h
;system exit
mov eax,1
mov ebx,0
int 80h;
This is my code when the numbers are hardcoded (this one multiplies the numbers correctly):
;this program adds two numbers, being able to solve with two digits
section .data
section .bss
var1 resb 2
var2 resb 2
result resb 2
tensdigit resb 2
onesdigit resb 2
section .text
global _start
_start:
;setup the variables
mov [var1], word 9
mov [var2], word 3
mov al, [var1]
mov bl, [var2]
mul bl
mov [result], ax
;divide by ten
mov ax, 0 ;set the register to 0! Very important to avoid errors
mov ax, [result]
mov bx, 10
div bx ;divide by ten
mov [tensdigit], al ;this should have 1 if using 12 (2 if 24, etc)
mov ax, [result]
sub ax, 10
mov [result], ax ;move new number into result
mov al, [result]
mov bl, 10
div bl
;find the remainder
mov [onesdigit], ah
add [tensdigit], word '0' ;add 0 to ensure it's considered a number
add [result], word '0'
add [onesdigit], word '0'
;print tensdigit
mov eax, 4
mov ebx, 1
mov ecx, tensdigit
mov edx, 2
int 80h
;print onesdigit
mov eax, 4
mov ebx, 1
mov ecx, onesdigit
mov edx, 2
int 80h
mov eax,1
mov ebx,0
int 80h;
Task: output the number in hexadecimal form to the console. After that print some string (let it be "String after num").
The first part is successful, but the second is not.
The input number is stored in memory by the num label.
String is stored in memory by the line label.
String length - lines.
Code:
global _start
section .data
num db 01111110b
temp db 0
line db 10, "String after num", 10
lines equ $-line
section .text
_start:
call write_hex ; write num in hex format
mov eax, 4 ; write "Hello world!"
mov ebx, 1 ;
mov ecx, line ;
mov edx, lines ;
int 80H ;
mov eax, 1 ; exit
xor ebx, ebx
int 80H
write_hex:
mov eax, [num]
mov [temp], eax
shr byte [num], 4
call to_hex_digit
call write_digit
mov eax, [temp]
mov [num], eax
and byte [num], 1111b
call to_hex_digit
call write_digit
ret
to_hex_digit:
add [num], byte '0'
cmp [num], byte '9'
jle end
add [num], byte 7
end: ret
write_digit:
mov eax, 4
mov ebx, 1
mov ecx, num
mov edx, 1
int 80H
ret
Output:
Thanks for any help.
I used an invalid register to store a temporary value. I replaced the register which will work with the temp from eax to al. See Jester's answer.
section .bss
num1 resb 4
result resb 4
section .data
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
INCREMENT equ 1
msg1 db 'Please enter an integer here:',0xA
len1 EQU $- msg1
msg2 db 'Your integer after being incremented is:',0xA
len2 EQU $- msg2
section .text
global _start:
_start:
mov eax, SYS_WRITE ; Prompting user to enter a number.
mov ebx, STDOUT
mov ecx, msg1
mov edx, len1
int 0x80
mov eax, SYS_READ ; Reading users number.
mov ebx, STDOUT
mov ecx, num1
mov edx, 4
int 0x80
mov eax, SYS_WRITE ; Writing second message.
mov ebx, STDOUT
mov ecx, msg2
mov edx, len2
int 0x80
mov eax, [num1] ; incrementing the user's number.
mov ebx, INCREMENT
add eax, ebx
mov [result], eax
mov eax, SYS_WRITE ; Printing out incremented number.
mov ebx, STDOUT
mov ecx, result
mov edx, 4
int 0x80
Just started learning basic assembly code today and I'm trying to increment user input numbers by 1. I am getting weird results when the number is any bigger than a single digit. What's the difference?
The problem is that your treat your input as numbers and not as strings. When you receive your input (string), you get an (ASCII) string as your return value. Increasing the first char(digit) by add eax, INCREMENT (compacted) does work, because the first ASCII char value of [num] contained in AL(lowest byte of EAX) is increased by one. This happens because the ASCII value of 0 is 48 and the ASCII value of 9 is 57.
If you think you increase these 'digits', you would in fact increase their ASCII values, which works well until you reach the one-digit-limit(0-9). Increasing 9 by one would result in : and not 10, as your may have expected because the ASCII value of 9 is 57 and adding one to it results in 58, which is the ASCII value of :.
So you would have to 'normalize' your 'numbers' before you operate on them with integer arithmetic. Transform them from ASCII strings to integer values.
Luckily for you, others have done this before you and optimized these approaches to the practical maximum. Look and search for atoi(ASCII to integer) and itoa(integer to ASCII). Then surround your arithmetical operations
mov eax, [num1] ; incrementing the user's number.
mov ebx, INCREMENT
add eax, ebx
mov [result], eax
with these functions.
I have code here that reads in input to determine the dimensions of a matrix/2d array and then reads in numbers one by one. Then it is SUPPOSED to spit out the smallest number.
However my comparison operator doesn't seem to be working? I've tried putting both as registers, with different variables and so on but for some reason eax with whatever happened to be the first entry in the array is ALWAYS smaller than the next number, even if this is clearly not the case.
So it always skips reassignment.
Code: Just skip straight to cmp eax,[num]
My guess is something is causing num, perhaps how its declared? Is always 'larger' than eax, is there extra fluff I am not aware of?
segment .bss
num: resw 1 ;For storing a number, to be read of printed....
nod: resb 1 ;For storing the number of digits....
temp: resb 2
matrix1: resw 200
m: resw 1
n: resw 1
i: resw 1
j: resw 1
small: resb 4 ; temp variable
buff resb 4
segment .data
msg1: db "Enter the number of rows in the matrix : "
msg_size1: equ $-msg1
msg2: db "Enter the elements one by one(row by row) : "
msg_size2: equ $-msg2
msg3: db "Enter the number of columns in the matrix : "
msg_size3: equ $-msg3
msg4: db "The Smallest Number is... : "
msg_size4: equ $-msg4
tab: db 9 ;ASCII for vertical tab
new_line: db 10 ;ASCII for new line
segment .text
global _start
_start:
;; code for reading number of rows and columns, this works fine.
mov eax, 4
mov ebx, 1
mov ecx, msg1
mov edx, msg_size1
int 80h
;; read in rows
mov ecx, 0
call read_num
mov cx, word[num]
mov word[m], cx
mov eax, 4
mov ebx, 1
mov ecx, msg3
mov edx, msg_size3
int 80h
;; read in columns
mov ecx, 0
call read_num
mov cx, word[num]
mov word[n], cx
mov eax, 4
mov ebx, 1
mov ecx, msg2
mov edx, msg_size2
int 80h
;; Reading in each element and storing it into the array
mov esi, 0
mov ebx, matrix1
;; init loop
mov word[i], 0
mov word[j], 0
;; Outer loop
i_loop:
mov word[j], 0
;; Inner Loop
j_loop:
;; A function
call read_num
;; Result of that function is now stored int he matrix
mov dx , word[num]
mov word[ebx + 2 * esi], dx
inc esi ;Incrementing array index by one....
inc word[j]
mov cx, word[j]
cmp cx, word[n]
jb j_loop
;; End Inner Loop
inc word[i]
mov cx, word[i]
cmp cx, word[m]
jb i_loop
;; End Outer Loop
;; Now begins the code to find the smallest number
mov eax, [matrix1]
;; Moves first element of Matrix1 into eax
;;; saves eax into small
mov [small], eax
;Loop through the matrix, check each number if its smaller than the first number in the array. AT the end print said number.
;Reading each element of the matrix.(Storing the elements in row major order).......
mov esi, 0
mov edi, matrix1
;; Reinit loop cters
mov word[i], 0
mov word[j], 0
;; Loop
i_loop2:
mov word[j], 0
j_loop2:
;eax will contain the array index and each element is 2 bytes(1 word) long
mov dx, word[edi+2*esi] ;
mov word[num] , dx
cmp eax,[num] ; compares eax and ebx
jle skip ;if eax is SMALLER than ebx, we can safely skip reassignment
;as our current value is already smallest.
mov eax, [num] ; stores new smallest number if the new number was smaller.
mov [small], eax
;; reassignment code is always skipped.
skip:
inc esi
inc word[j]
mov cx, word[j]
cmp cx, word[n]
jb j_loop2
inc word[i]
mov cx, word[i]
cmp cx, word[m]
jb i_loop2
; code to output the smallest number
;; Some ui text.
mov eax, 4
mov ebx, 1
mov ecx, msg4
mov edx, msg_size4
int 80h
mov ecx, 0
;; Now the actual smallest number
mov eax, 4 ; system_write
mov ebx, 1 ; stdout
mov ecx, [small] ; move smallest element to accumulator
add ecx, 48 ; convert to ascii representation
mov [buff], ecx ; move to memory
mov ecx, buff
mov edx, 4 ; size, 4 bytes
int 80h
exit:
mov eax, 1
mov ebx, 0
int 80h
;Function to read a number from console and to store that in num
read_num:
pusha
mov word[num], 0
loop_read:
mov eax, 3
mov ebx, 0
mov ecx, temp
mov edx, 1
int 80h
cmp byte[temp], 10
je end_read
mov ax, word[num]
mov bx, 10
mul bx
mov bl, byte[temp]
sub bl, 30h
mov bh, 0
add ax, bx
mov word[num], ax
jmp loop_read
end_read:
popa
ret
Oh yes, several hours of fidgeting and seconds after this post I figured out exactly why. Turns out yes, the way I declared "num" yes indeed added in extra information. I changed it to resb 4 and it works.
Crabbaskets.