I'm having problems adding numbers in an array -- x86 MASM assembly - arrays

I have to create a random range of 100 counts of numbers from 27 to 58 and then add up all the numbers in the 100 positions for a total amount. However, when I do that I get a random number and ninety-nine 32's as a result. I've searched everywhere and tried possible solutions but I'm either getting the same result or random garbage. Can someone offer some help?
INCLUDE irvine32.inc
.data
a DWORD 27
b DWORD 58
delta DWORD ?
source DWORD 100 DUP(?)
prompt BYTE "The sum of the 100 counts in array is ",0
.code
main PROC
Call Randomize
mov edi, 0
mov edi, OFFSET delta
mov esi, OFFSET source
mov eax, b
sub eax, a
inc eax
mov delta, eax
mov ecx, LENGTHOF source
mov eax, 0
L1:
mov eax, delta
call randomrange
add eax, a
mov source, eax
call writedec
mov al, " "
call writechar
loop L1
call crlf
call crlf
mov ecx, SIZEOF source
mov edx, OFFSET prompt
call writestring
l2:
add eax,[esi]
add esi, TYPE delta
call writedec
mov al, " "
call writechar
loop l2
exit
main ENDP
END main

I assume randomrange leaves its random number in EAX.
In the L1 loop, you add A to EAX to get your random value and then copy it to the first element of SOURCE every time through the L1 loop. That's why the first element is random, but the rest of the array isn't touched. (Note that you have the same problem in L2 -- you always get the value to print from the first element of SOURCE.)

Related

how to display the count in MASM?

this is my code for a MASM assignment, the assignment is:
Write an application that does the following:
Declare a 32-bit integer array with 50 elements with uninitialized values
Fill the 32-bit array with 50 random integers
Loop through array, and display each value, and count the number of negative values
After final loop finishes, display the count
I have it doing everything but displaying the count of negative numbers. If anyone can tell me where I am wrong that would be super helpful I have been working on this for some time.
INCLUDE Irvine32.inc
.data
myArray SWORD 50 DUP(?)
count DWORD 0
.code
main proc
call randomize
mov esi, offset myArray
mov ecx, lengthof myArray
L1:
call Random32
call WriteInt
call Crlf
mov [esi], eax
add esi, 4
loop L1
mov eax, offset myArray
mov esi, lengthof myArray
L2:
cmp dword ptr[esi], 0
jge L3
DWORD count
L3:
add esi, 4
loop L2
mov eax, count
call WriteDec
call Crlf
exit
main ENDP
END main

How to make assembly program call new line after 5 outputs of fibonacci

So my assignment was to have the user enter a number of fibonacci terms to print, and the program would print those out in order. However it also calls for there to be a new line after five terms are printed. The other requirement is that the masm "loop" instruction has to be used in the loop that calculates the fibonacci numbers. How would I implement this without an infinite loop? This is what it I have right now. It calculates the fibonacci fine but not when I try to add a new line:
.data
fib_count DWORD ?
num1 DWORD 0
num2 DWORD 1
sum DWORD 0
counter DWORD 0
spaces BYTE " ",0
.code
main PROC
;Display fibonacci
mov ecx, fib_count ;fib_count is the number of terms the user entered
;printing first 1
mov eax, 1
call WriteDec
mov edx, OFFSET spaces
call WriteString
dec ecx
print_loop:
mov eax, num1
add eax, num2
mov sum, eax
mov eax, num2
mov num1,eax
mov eax, sum
mov num2,eax
mov eax, sum
call WriteDec
inc counter
mov eax, counter
cmp eax, 5
je new_line
mov edx, OFFSET spaces
call WriteString
loop print_loop
new_line:
call crlf
loop print_loop
You need a jump instruction just before new_line to go around the new_line code:
; ...
call WriteString
loop print_loop
jmp short done
new_line:
call crlf
loop print_loop
done:
; ...

Assembly: Issues with Indexing

I'm having trouble figuring out how to do the indexing in my loops. I know esi is used for indexing, so I'm attempting to use that...
scores DWORD MAXIMUMSCORES DUP(0)
optionPromptMsg byte "Type 1 to continue or -1 to exit: ", 0
scorePromptMsg byte "Enter your numeric score (0-100): ", 0
scoreErrorMsg byte "Score out of range (0-100)!", 0
optionErrorMsg byte "Only 0 or 1 allowed in option specification!", 0
resultMsg byte " scores have been entered.", 0
.code
main proc
mov esi, 0
L1:
mov edx, offset optionPromptMsg
call WriteString
call ReadInt
mov ebx, 1
cmp eax, ebx
je L2
mov ebx, -1 //99% sure my main is okay
cmp eax, ebx
je L3
mov ebx, -2
mov ecx, 2
cmp ebx, eax
ja L4
cmp eax, ecx
ja L4
L2: call NextScore
jmp L5
L4: mov edx, offset optionErrorMsg
call WriteString
call Crlf
jmp L5
L5:
loop L1
L3 : call WriteScore
exit
main ENDP
WriteScore PROC USES esi //Thought was somehow make esi global?
mov eax, lengthof scores //total number of items added to array
call writeInt
mov edx, offset resultMsg
call WriteString
mov esi,0
L1:
mov eax, scores[esi *4]
call writeInt //writes the numbers in the array
inc esi
loop L1
mov eax, 5000
call Delay
ret
WriteScore ENDP
NextScore PROC USES esi
mov edx, offset scorePromptMsg
call WriteString
call ReadInt
mov ebx, 0
mov ecx, 100
cmp ebx, eax
ja L1
cmp eax,ecx
ja L1
jmp L2
L1:
mov edx, offset scoreErrorMsg
call WriteString
call Crlf
L2:
mov scores[esi*4], eax //gets the next number and puts it in the array
inc esi
ret
NextScore ENDP
When I run it, and add 3 items to the array, it for whatever reason says the lengthof scores is 20, and then when it prints out the array, the numbers aren't even close to what I'm expecting, normally in the millions or just 0.
Any suggestions are much appreciated!
You have a couple issues. One is that you don't seem to understand what the USES directive on a procedure/function is for. If you use USES and list a register(s) then that tells the assembler to save the value of those registers on the stack, and restore them just before the function exits. This means that any change you make to that register in that function will not be seen by the function that called it.
The MASM manual says this about USES:
Syntax: USES reglist
Description:
An optional keyword used with PROC. Generates code to push the
value of registers that should be preserved (and that will be
altered by your procedure) on the stack and pop them off when the
procedure returns.
The <reglist> parameter is a list of one or more registers. Separate
multiple registers with spaces.
Since you seem to want changes to ESI made in the function NextScore to be seen by the calling function you will want to remove the USES statement from that procedure. Change:
NextScore PROC USES esi
to:
NextScore PROC
Now when you increment ESI in next score it won't be undone when the function exits.
Another issue is that the lengthof pseudo-opcode does:
lengthof: Returns the number of items in array variable.
It may not be clear but this pseudo-opcode is the number of elements in the array when the code was assembled. You define the array of scores like this:
scores DWORD MAXIMUMSCORES DUP(0)
The scores array will always have a lengthof value of MAXIMUMSCORES. Rather than use lengthof what you should be doing is simply using the ESI register. You already use ESI to keep a count of elements you have added to the array. So this code:
WriteScore PROC USES esi ; Thought was somehow make esi global?
mov eax, lengthof scores ; total number of items added to array
call WriteInt
Can be changed to:
WriteScore PROC USES esi ; Thought was somehow make esi global?
mov eax, esi ; esi = number of items added to array
call WriteInt
Another issue is that it appears you don't know how the loop instruction works. From the [x86 Instruction Set] the loop instruction does:
Performs a loop operation using the ECX or CX register as a counter.
Each time the LOOP instruction is executed, the count register is
decremented, then checked for 0. If the count is 0, the loop is
terminated and program execution continues with the instruction
following the LOOP instruction. If the count is not zero, a near jump
is performed to the destination (target) operand, which is presumably
the instruction at the beginning of the loop.
In your code you never set ECX to the number of times you wish to loop, so it will use whatever value happens to be in ECX . This is why you have a lot of extra numbers printed out. ECX needs to be initialized. Since you want to loop through all the scores entered, you simply move ESI to ECX. Your WriteScore function did:
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
We can modify it to be:
mov ecx,esi ; Initialize ECX loop counter to number of scores added
; to the array.
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
Now we just loop through the number of scores (ESI) the user actually entered.
With these changes in mind your program could look something like this:
INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
INCLUDELIB user32.lib
INCLUDELIB kernel32.lib
MAXIMUMSCORES equ 20
.data
scores DWORD MAXIMUMSCORES DUP(0)
optionPromptMsg byte "Type 1 to continue or -1 to exit: ", 0
scorePromptMsg byte "Enter your numeric score (0-100): ", 0
scoreErrorMsg byte "Score out of range (0-100)!", 0
optionErrorMsg byte "Only 0 or 1 allowed in option specification!", 0
resultMsg byte " scores have been entered.", 0
.code
main proc
mov esi, 0
L1:
mov edx, offset optionPromptMsg
call WriteString
call ReadInt
mov ebx, 1
cmp eax, ebx
je L2
mov ebx, -1 ; 99% sure my main is okay
cmp eax, ebx
je L3
mov ebx, -2
mov ecx, 2
cmp ebx, eax
ja L4
cmp eax, ecx
ja L4
L2: call NextScore
jmp L5
L4: mov edx, offset optionErrorMsg
call WriteString
call Crlf
jmp L5
L5:
loop L1
L3: call WriteScore
exit
main ENDP
WriteScore PROC USES esi ; We make changes to ESI not visible to caller
; since we don't intend to change the number of scores
; with this function. Any change to ESI in this function
; will not appear to the caller of this function
mov eax, esi ; total number of items added to array in ESI
call WriteInt
mov edx, offset resultMsg
call WriteString
mov ecx,esi
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
mov eax, 5000
call Delay
ret
WriteScore ENDP
NextScore PROC ; We want changes to ESI to exist after we exit this function. ESI
; will effectively act as a global register.
mov edx, offset scorePromptMsg
call WriteString
call ReadInt
mov ebx, 0
mov ecx, 100
cmp ebx, eax
ja L1
cmp eax,ecx
ja L1
jmp L2
L1:
mov edx, offset scoreErrorMsg
call WriteString
call Crlf
L2:
mov scores[esi*4], eax ; gets the next number and puts it in the array
inc esi
ret
NextScore ENDP
END
Sample output of this:
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 10
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 20
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 40
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 650
Score out of range (0-100)!
Type 1 to continue or -1 to exit: 99
Only 0 or 1 allowed in option specification!
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 100
Type 1 to continue or -1 to exit: -1
+5 scores have been entered.+10+20+40+650+100

How to move and display array values from one to another in Assembly Language?

I am trying to move the values in Array1 to Array2, and then display them. I have been working on this and could not figure it out at all. Would anyone please help me? Thanks
INCLUDE Irvine32.inc
INCLUDE macros.inc
.data
Array1 DWord 2,4,6,8,10
Array2 DWord 5 Dup(0)
.code
main PROC
mov edx, OFFSET Array1
mov esi, OFFSET Array2
mov ecx, LENGTHOF Array1
mov eax, 0
Call Dumpregs
Call Dumpregs
L1:
mWrite "Hello"
Call CRLF
Loop L1
Call Dumpregs
L2:
mov eax, [edx]
mov [esi], eax
add esi, 4
add edx, 4
Loop L2
exit
main ENDP
END main
Your L2 loop cannot produce the desired result since the preceding code wiped ECX clean (You used loop L1). To copy the array you need to re-initialize ECX. Also it's best to setup the pointers EDX and ESI close to this L2 loop because perhaps there is a risk of them being modified by all those preceding (macro)calls!
mov edx, OFFSET Array1
mov esi, OFFSET Array2
mov ecx,5
L2:
mov eax,[edx]
mov [esi],eax
add esi, 4
add edx, 4
loop L2

Array access in MASM

I'm having some difficulty with my array accessing in MASM. I've got a very large array and a temp variable like so:
.data
array DWORD 65000 DUP (0)
temp DWORD 0
In my main, I've got this to fill it:
mov esi, offset array
mov edi, 0
mov ecx, 0
fill:
mov [esi], ecx
add esi, 4
inc ecx
cmp ecx, 65000
jl fill
mov esi, offset array ;reset the array location to the start
After, I want to access the array with this loop:
mark:
mov temp, 4 ;get another 4 to temp to move along the array
add esi, temp ;add temp to esi to keep moving
mov edx, [esi] ;access the current value
cmp esi, 20 ;just trying to get first few elements
jmp mark
exit
main ENDP
END main
I always have an access violation error, with the break at the line where I try to access the current value. This occurs on the very first loop as well. Any idea why this is happening? Thanks!
Your code will work to an extent, however:
mark:
mov temp, 4
add esi, temp ;Incrementing before first loop means you miss the first stored value
mov edx, [esi]
cmp esi, 20 ;ESI is the address your are accessing, not a count
jmp mark ;This loop will be infinite

Resources