Bob
Bob

Reputation: 1396

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!

Upvotes: 0

Views: 187

Answers (1)

Michael Petch
Michael Petch

Reputation: 47563

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

Upvotes: 1

Related Questions