在 x86 程序集中生成伪随机字符

Generating a pseudo-random character in x86 assembly

我正在学习汇编,我找到了这段代码:

; 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

现在我知道了,这是方法myrand中的线性同余生成器。
我的问题是 myrand 中的数字如何导致 randletter 中 ASCII 中从 97 到 122 的数字?以及为什么他们在 myrand 中有 add al, a。这有什么帮助?

小写字母的 ASCII 码从 'a' 的 97 到 'z' 的 122 不等。
myrand(25) 的输出是从 0 到 25。

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

无论 myseed 中的值如何,除法 div edi 都会根据 EDI=25+1 始终产生 0 到 25 之间的余数。此余数成为 myrand 函数的结果。

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

导致 myseed 新值的计算仅对随机数分布的质量很重要。
输出范围的限制完全取除法的余数.