I'm having a bit of trouble understanding the rlwinm
PPC Assembly instruction (Rotate Left Word Immediate Then AND with Mask).
I am trying to reverse this part of a function
rlwinm r3, r3, 0, 28, 28
I already know what r3
is. r3
in this case is a 4 byte integer but I am not sure exactly what this instruction rlwinm
is doing to it.
By the way, this is on a 32 bit machine.
Your understanding is not quite right. As per the IBM link on this instruction, the form you're seeing is:
rlwinm <target=r3>, <source=r3>, <shift=0>, <begin-mask=28>, <end-mask=28>
Hence no actual shift is involved. And the actual mask used for the AND
operation is constructed from the begin
and end
mask positions, it's not given as an explicit argument(a).
In this case, since both positions are 28, the mask is simply a single bit, as per the linked page (slightly paraphrased):
If the begin-mask value is less than the end-mask value plus one, then the mask bits between and including the starting point and the end point are set to ones. All other bits are set to zeros.
So the instruction you're seeing is nothing more complicated than a single AND
operation.
(a) There is a form that allows you to specify the actual mask (assuming it consists of contiguous one-bits) but it's the four-argument version and really just syntactic sugar that the assembler can turn into the five-argument one.
@paxdiablo's answer is a correct, but to add some more context:
The various r*
instructions (rlwinm, rlwimi, etc) are designed for extracting bit fields whose size is known at compile time, for example C struct bitfields, or even just splitting a word into bytes (which may be faster with one lw
and four rlwinm
instructions than several separate lbzu
s).
lw r4, r3 ; load the word at the address pointed at by r3
rlwinm r5, r4, 8, 24, 31 ; first byte in r5
rlwinm r6, r4, 16, 24, 31 ; second byte in r6
rlwinm r7, r4, 24, 24, 31 ; third byte in r7
rlwinm r8, r4, 0, 24, 31 ; fourth byte in r8, identical to andi r8, r4, 255
The rlwinm
instructions can also be used, as in this case, as a special form of andi
for contiguous sets of bits. Since instructions in PowerPC are always 32 bits, instructions taking immediate values have only 16 bits to hold those values - so if you want to mask a set of bits that crosses the high/low half-word boundary, say 23 to 8, you need to use multiple operations.
lis r4, r4, 0x00ff ; first set bits 23 to 16 of the mask
ori r4, r4, 0xff00 ; then bits bits 15 to 8
and r3, r3, r4 ; then perform the actual masking
However, with the rlwinm
instructions, we can perform that same operation in a single instruction:
rlwinm r3, r3, 0, 8, 23
In your case, the value probably holds flags for something and this instruction is extracting one of them. The next instruction is probably a conditional branch on r3
.
ETA: Peter Cordes corrected out some of my mistakes, for which I am grateful, and added that it was probably unnecessary to use rlwinm
in this case, and that it may simply be a peculiarity of the compiler that causes this instruction to be generated instead of andi
.