CHAPTER 20. LINEAR CONGRUENTIAL GENERATOR CHAPTER 20. LINEAR CONGRUENTIAL GENERATOR
; 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)
; the LI instruction is coalesced by IDA from LUI and ORI
li $a0, 0x3C6EF35F
addu $v0, $a0
; store to rand_state:
sw $v0, (rand_state & 0xFFFF)($v1)
jr $ra
andi $v0, 0x7FFF ; branch delay slot
Wow, here we see only one constant (0x3C6EF35F or 1013904223). Where is the other one (1664525)?
It seems that multiplication by 1664525 is done by just using shifts and additions! Let’s check this assumption:
#define RNG_a 1664525
int f (int a)
{
return a*RNG_a;
}
Listing 20.6: Optimizing GCC 4.4.5 (IDA)
f:
sll $v1, $a0, 2
sll $v0, $a0, 4
addu $v0, $v1, $v0
sll $v1, $v0, 6
subu $v0, $v1, $v0
addu $v0, $a0
sll $v1, $v0, 5
addu $v0, $v1
sll $v0, 3
addu $a0, $v0, $a0
sll $v0, $a0, 2
jr $ra
addu $v0, $a0, $v0 ; branch delay slot
Indeed!
20.4.1 MIPS relocations
We will also focus on how such operations as load from memory and store to memory actually work. The listings here are
produced by IDA, which hides some details.
We’ll run objdump twice: to get a disassembled listing and also relocations list: