anon
anon

Reputation:

Generating a pseudo-random character in x86 assembly

I'm learning assembly, and I found this code:

; Initialized seed value
    xor [myseed], esp

    ; Generate random string
    call randletter
    mov [message], al       ; Write 1st letter

; myrand gives a pseudo-random number in range 0..max
; inputs:
;   edi - max value
; outputs:
;   eax - generated value
myrand: mov eax, [myseed]       ; Load state of generator
        mov ecx, 4000000001 
        mul ecx                 ; Multiply state var by a constant
        add eax, 3333333333     ; Add another constant
        mov [myseed], eax       ; And save the result
        xor edx, edx
        inc edi
        div edi                 ; Divide state var in edx:eax by (max+1) in edi
        mov eax, edx            ; div instruction writes remainder into edx, so copy to eax
        ret

; randletter gives a random lowercase letter
; inputs: no
; outputs:
;   al - random lowercase letter (ASCII code)
randletter:
        mov edi, 25
        call myrand
        add al, 'a'
        ret


    section    .data

myseed: dd  123456789

Now I know that, this is linear congruential generator in the method myrand.
My question is how the number from myrand can cause the number from 97 to 122 in ASCII in randletter? And why they have add al, a in myrand. How can that help?

Upvotes: 1

Views: 928

Answers (1)

Sep Roland
Sep Roland

Reputation: 39176

The ASCII codes for the lowercase letters vary from 97 for 'a' to 122 for 'z'.
The output from myrand(25) is from 0 to 25.

randletter:
        mov edi, 25
        call myrand    ; -> EAX == [0,25]
        add al, 'a'    ; -> AL == [0,25] + 97 == [97,122] == ['a','z']
        ret

No matter the value in myseed, the division div edi will, given that EDI=25+1, always produce a remainder from 0 to 25. This remainder becomes the result of the myrand function.

EDI=25
        ...
        mov [myseed], eax   ; And save the result
        xor edx, edx        ; EDX=0
        inc edi             ; -> EDI == 25 + 1 == 26
        div edi             ; Divide EDX:EAX by 26 -> remainder EDX == [0,25]
        mov eax, edx        ; return result in EAX
        ret

The calculation that leads to the new value of myseed is only important for the quality of the distribution of the random numbers.
The restriction of the output range is exclusively obtained from taking the remainder of the division.

Upvotes: 2

Related Questions