Search code examples
arraysassemblyx86masm

Restoring an array's original value by utilizing the stack?


enter image description hereI have an assignment for class that has us creating a CreateRandomString proc that will create strings of differing values and each time will store them in arrayString. Then in main proc a writeLoop will iterate through each string for a total of 20 strings 20 different times. Each string is to be of random length and random content but all must be capital letters. My program works succesfully except for the fact that the arrayString does not get properly reset due to the global nature of a lot of the things i'm using. I'm sure I could utilize the stack in some way but I am not quite sure how. Could one somehow push some cleared version of the array and then pop it when it needs to generate a new string? I am truly at a loss on what I am missing here. I am quite new to assembly and am all for any advice or pointers anyone has on this issue or a better way to approach the problem. I also want to note I utilized a proc from the Irvine32 library called RandomRange which just took the EAX value of 100 and rolls a random value from 0-(100-1).


;.386
;.model flat,stdcall
;.stack 4096
;ExitProcess proto,dwExitCode:dword
INCLUDE Irvine32.inc

.data
arrayString BYTE 100 DUP (?)
mainLoopCounter DWORD 20

.code

CreateRandomString proc
    mov ESI, OFFSET arrayString
    mov ECX, EAX ;Length of string

storeLoop:
    mov EAX, 26
    call RandomRange
    add EAX, 65
    mov BYTE PTR [ESI], AL
    inc esi
    loop storeLoop
    call CRLF
    ret
CreateRandomString endp
main proc
    call Randomize
mainL:
    mov EAX, 100
    call RandomRange
    call CreateRandomString

    mov ESI, OFFSET arrayString
    mov ECX, LENGTHOF arrayString
writeLoop:
    mov AL, BYTE PTR [ESI]
    call WriteChar
    inc ESI
    loop writeLoop
    mov ECX, mainLoopCounter
    dec mainLoopCounter
    loop mainL

    Invoke ExitProcess,0
main endp
end main

As far as methods I have attempted to solve the problem, I have been tampering with the stack because it is the one method we've learned for restoring things to their original values. Since ECX and ESI were being tampered with in other parts of the program, for the beginning of my storeLoop I did push ESI and push ECX and then popped them in their respective orders after storeLoop ended to no avail at all. I think this is because ESI is really just an address to store the char thats generated and is incremented and changing constantly, and ECX does not matter all that much in the context given. I need each string to be of random content, random length instead of just building on the previous until it crashes.


Solution

  •     mov ESI, OFFSET arrayString
        mov ECX, LENGTHOF arrayString
    writeLoop:
    

    Don't initialize the counter with LENGTHOF arrayString. You need to setup ECX with the same number that you gave to CreateRandomString:

      mov  EAX, 100
      call RandomRange        ; -> EAX
      push eax                ; (1)
      call CreateRandomString
      pop  ecx                ; (1)
      mov  ESI, OFFSET arrayString
    writeLoop:
    

    Something to watch out for

    Your RandomRange can return in EAX a number from 0 to 99. The CreateRandomString procedure will not function correctly when fed with a zero! Best never pass a zero to this proc:

    Redo:
      mov  EAX, 100
      call RandomRange        ; -> EAX
      test eax, eax
      jz   ReDo
      push eax                ; (1) [1,99]
      call CreateRandomString
      pop  ecx                ; (1)
      mov  ESI, OFFSET arrayString
    writeLoop:
    

    You don't need to use the loop instruction all the time!

    mov ECX, mainLoopCounter
    dec mainLoopCounter
    loop mainL
    

    This can be written simpler and will execute faster:

    dec  mainLoopCounter
    jnz  mainL