1.23. LINEAR CONGRUENTIAL GENERATOR
my_srand PROC
LDR r1,|L0.52| ; load pointer to rand_state
STR r0,[r1,#0] ; save rand_state
BX lr
ENDP
my_rand PROC
LDR r0,|L0.52| ; load pointer to rand_state
LDR r2,|L0.56| ; load RNG_a
LDR r1,[r0,#0] ; load rand_state
MUL r1,r2,r1
LDR r2,|L0.60| ; load RNG_c
ADD r1,r1,r2
STR r1,[r0,#0] ; save rand_state
; AND with 0x7FFF:
LSL r0,r1,#17
LSR r0,r0,#17
BX lr
ENDP
|L0.52|
DCD ||.data||
|L0.56|
DCD 0x0019660d
|L0.60|
DCD 0x3c6ef35f
AREA ||.data||, DATA, ALIGN=2
rand_state
DCD 0x00000000
It’s not possible to embed 32-bit constants into ARM instructions, so Keil has to place them externally and
load them additionally. One interesting thing is that it’s not possible to embed the 0x7FFF constant as
well. So what Keil does is shiftingrand_stateleft by 17 bits and then shifting it right by 17 bits. This is
analogous to the(rand_state≪17)≫ 17 statement in C/C++. It seems to be useless operation, but what it
does is clearing the high 17 bits, leaving the low 15 bits intact, and that’s our goal after all.
Optimizing Keil for Thumb mode generates mostly the same code.
1.23.4 MIPS.
Listing 1.322: Optimizing GCC 4.4.5 (IDA)
my_srand:
; store $a0 to rand_state:
lui $v0, (rand_state >> 16)
jr $ra
sw $a0, rand_state
my_rand:
; load rand_state to $v0:
lui $v1, (rand_state >> 16)
lw $v0, rand_state
or $at, $zero ; load delay slot
; multiplicate rand_state in $v0 by 1664525 (RNG_a):
sll $a1, $v0, 2
sll $a0, $v0, 4
addu $a0, $a1, $a0
sll $a1, $a0, 6
subu $a0, $a1, $a0
addu $a0, $v0
sll $a1, $a0, 5
addu $a0, $a1
sll $a0, 3
addu $v0, $a0, $v0
sll $a0, $v0, 2
addu $v0, $a0
; add 1013904223 (RNG_c)