NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: ZimbuTheMonkey on March 29, 2014, 01:10:19 AM
-
Hello,
For an assignment, I have to compute the average of 10 numbers. I had it summing into a buffer correctly, but then I changed something and it no longer works (the sum is of order of magnitudes incorrect).
https://www.dropbox.com/s/pt8rqhkznaiuqjl/assign1.asm
There's the entire thing. I could use some help understanding where it's going wrong.
Thanks!
EDIT: So just with testing (printing out values in EAX), both get_num and print_num functions are working just fine. For example, if I input a 2, and add the value of 50 to eax and then call print_num, the output is 52.
-
Your "total" is too small. You've reserved only two bytes, and put eax into it, overwriting your InputBuffer. Make it "resd 1". There may be more (only getting 9 numbers?), but that's what I see so far...
Best,
Frank
-
That worked, thanks!
I had it at 2 because I figured 990 would be the maximum value it would ever have stored.
As for the loop, it's getting 10 numbers.
-
Well 990 would fit in two bytes, but you'd have to use ax, not eax. I don't suggest you do this.
For your current problem: [numlist + ecx * 4], not * 32. You want number of bytes, not bits. The "scale" can only be 1 (default), 2, 4, or 8.
One of us is having a problem counting to 10! Easily fixed, in any case.
Best,
Frank
...so other people can see it...
section .data
; Welcome message
wellmsg db "This program will compute the average of 10 2-digit numbers.",0xA
wellmsglen equ $-wellmsg
askmsg db "Enter number: "
askmsglen equ $-askmsg
section .bss
numlist: resb 10 ; list of our numbers
total: resd 1 ; to store the sum of the 10 numbers
inputBufferSize equ 3 ; three characters (num1, num2 and enter key)
inputBuffer resb inputBufferSize
inputBufferEnd:
outputBufferSize equ 10
outputBuffer resb outputBufferSize
outputBufferEnd:
section .text
global _start
_start:
; print welcome message once
mov eax, 4
mov ebx, 1
mov ecx, wellmsg
mov edx, wellmsglen
int 0x80
; loop to run 10 times to read input and store number
mov ecx, 0
prompt:
; store count
push ecx
; prompt message
mov eax, 4
mov ebx, 1
mov ecx, askmsg
mov edx, askmsglen
int 0x80
; get input number
call get_num
add [total], eax
pop ecx
inc ecx
cmp ecx, 9
jne prompt
mov eax, [total]
call print_num
;exit
mov eax, 1
mov ebx, 0
int 0x80
get_num:
; input into buffer
mov eax, 3
mov ebx, 0
mov ecx, inputBuffer
mov edx, inputBufferSize
int 0x80
; eax = length of string
; make esi the start of the string
mov esi, inputBuffer
; make edi the end of the string
mov edi, inputBuffer
add edi, eax
dec edi
mov eax, 0
get_num_loop:
mov edx, 10
mul edx ; edx:eax = eax * operand
mov edx, 0
mov dl, [esi]
sub dl, 0x30
inc esi
add eax, edx
cmp esi, edi
jne get_num_loop
ret ; eax = inputed value
print_num:
; point to the end of the buffer
mov edi, outputBufferEnd
print_num_loop:
; move one character left
dec edi
; set up division
mov edx, 0
mov ebx, 10
div ebx ; eax = edx:eax / ebx, remainder in edx
; put the remainder on the buffer
add dl, 0x30 ; make it ASCII first
mov [edi], dl
; if after the above division, eax != 0, continue to loop, otherwise exit the loop
cmp eax, 0
jne print_num_loop
; set up registers and make system call
mov eax, 4
mov ebx, 1
mov ecx, edi
mov edx, outputBufferEnd
sub edx, edi
int 0x80
ret
-
EDIT: Got it, though I'm not sure if it's the smartest way to do it:
; print welcome message once
mov eax, 4
mov ebx, 1
mov ecx, wellmsg
mov edx, wellmsglen
int 0x80
call print_newline
; loop to run 10 times to read input and store number
mov ecx, 0
prompt:
; store count
push ecx
; prompt message
mov eax, 4
mov ebx, 1
mov ecx, askmsg
mov edx, askmsglen
int 0x80
;numbered prompt (store loop iteration + 1 in EAX, then print it)
pop ecx
push ecx
mov eax, ecx
inc eax
call print_num
call print_colon
call print_space
Yeah, I'm silly. I figured it after thinking to myself "why exactly am I scaling by 32 again?". :p
So the thing is done and operational. However, at the moment this is how the user will see the looped prompt:
Enter number: 11
Enter number: 28
Enter number: 19... etc.
But I want it to be:
Enter number #1: 11
Enter number #2: 28... etc.
I'm trying to use the ECX loop counter in there somehow to be the numbered part of it, but I am failing miserably.
-
Something like this? (not complete)
section .data
; Welcome message
wellmsg db "This program will compute the average of 10 2-digit numbers.",0xA
wellmsglen equ $-wellmsg
askmsg db "Enter number #"
askmsglen equ $-askmsg
section .bss
numlist: resb 10 ; list of our numbers
total: resd 1 ; to store the sum of the 10 numbers
inputBufferSize equ 3 ; three characters (num1, num2 and enter key)
inputBuffer resb inputBufferSize
inputBufferEnd:
outputBufferSize equ 10
outputBuffer resb outputBufferSize
outputBufferEnd:
section .text
global _start
_start:
; print welcome message once
mov eax, 4
mov ebx, 1
mov ecx, wellmsg
mov edx, wellmsglen
int 0x80
; loop to run 10 times to read input and store number
mov ecx, 0
prompt:
; store count
push ecx
; prompt message
mov eax, 4
mov ebx, 1
mov ecx, askmsg
mov edx, askmsglen
int 0x80
; pop eax ; get loop cunter back
; push eax ; put it back
mov eax, [esp]
inc eax ; we want to start with "1", not "0"
call print_num
; need a space here, maybe a ":"
mov al, ':'
call print_char
mov al, ' '
call print_char
; get input number
call get_num
add [total], eax
pop ecx
inc ecx
cmp ecx, 9
jne prompt
mov eax, [total]
call print_num
;exit
mov eax, 1
mov ebx, 0
int 0x80
get_num:
; input into buffer
mov eax, 3
mov ebx, 0
mov ecx, inputBuffer
mov edx, inputBufferSize
int 0x80
; eax = length of string
; make esi the start of the string
mov esi, inputBuffer
; make edi the end of the string
mov edi, inputBuffer
add edi, eax
dec edi
mov eax, 0
get_num_loop:
mov edx, 10
mul edx ; edx:eax = eax * operand
mov edx, 0
mov dl, [esi]
sub dl, 0x30
inc esi
add eax, edx
cmp esi, edi
jne get_num_loop
ret ; eax = inputed value
print_num:
; point to the end of the buffer
mov edi, outputBufferEnd
print_num_loop:
; move one character left
dec edi
; set up division
mov edx, 0
mov ebx, 10
div ebx ; eax = edx:eax / ebx, remainder in edx
; put the remainder on the buffer
add dl, 0x30 ; make it ASCII first
mov [edi], dl
; if after the above division, eax != 0, continue to loop, otherwise exit the loop
cmp eax, 0
jne print_num_loop
; set up registers and make system call
mov eax, 4
mov ebx, 1
mov ecx, edi
mov edx, outputBufferEnd
sub edx, edi
int 0x80
ret
print_char:
; prints the character in al
push edx
push ecx
push ebx
push eax ; must be pushed last - it's our "buffer"
mov ecx, esp ; our buffer
mov edx, 1 ; just one
mov ebx, 1
mov eax, 4
int 80h
pop eax
pop ebx
pop ecx
pop edx
ret
Edit: well I see you've come up with essentially the same thing...
Best,
Frank
-
Knowing that I did it in a similar fashion to yours is reassuring, to say the least.
-
Don't feel too good about it - the reason I can spot mistakes (like your original one) is that I make a lot of them. :)
Best,
Frank
-
I used your print_char function in my program.
Seems like a much smarter way than to define all the various chars I need individually.
Thanks again for the help, I appreciate it!