I've had a couple of courses that touched on ARMv8 assembly, but both teachers described LDUR/STUR instructions a different way and now I've become pretty lost. Can someone help to clarify?
If I had the instruction:
LDUR R3, [R1, #8]
I'll be putting the answer in R3, but what am I taking from R1 and how does the offset operate? Is it like a logical shift? The ARM manual describes it as "byte offset" but then doesn't describe how that offset functions on R1. Do I shift the value stored in R1 (say R1 has value 50 in it) or is there a memory address outside of the R1 that I need to be thinking about? Other sources say I need to think of R1 as an array somehow?
LDUR is Load (unscaled) Register. It loads a value (32-bits or 64-bits) from an address plus an offset to a register. unscaled
means that in the machine-code, the offset will not be encoded with a scaled offset like ldr
uses, i.e. no shift will be applied to the immediate offset bits. The offset (simm signed immediate) will be added to the base register Xn|SP.
Thus it's possible to use displacements that aren't a multiple of 4 or 8 with ldur
, unlike with ldr
These are the prototypes for LDUR:
-- loads a 32-bit value
LDUR <Wt>, [<Xn|SP>{, #<simm>}]
-- loads a 64-bit value
LDUR <Xt>, [<Xn|SP>{, #<simm>}]
STUR is Store (unscaled) Register and works in the same way but it stores the value in a register to memory.
These are the prototypes for STUR:
-- stores a 32-bit register
STUR <Wt>, [<Xn|SP>{, #<simm>}]
-- stores a 64-bit register
STUR <Xt>, [<Xn|SP>{, #<simm>}]
LDUR/STUR allow accessing 32/64-bit values when they are not aligned to the size of the operand. For example, a 32-bit value stored at address 0x52.
In your example,
LDUR R3, [R1, #8]
this instruction will load to R3
the value pointed by R1
plus 8
bytes. This is what the ARM Reference Manual means by byte offset
.
So if R1
holds the value 0x50
, this will load the value stored at address 0x58
. The value of R1
will not be modified.
The instruction LDR R3, [R1, #8]
(LDR (immediate) the Unsigned offset variant) produces the same operation, however, the prototype is different:
-- loads a 32-bit value
LDR <Wt>, [<Xn|SP>{, #<pimm>}]
-- loads a 64-bit value
LDR <Xt>, [<Xn|SP>{, #<pimm>}]
The immediate offset pimm is different, LDUR uses a simm. This means that the offset is interpreted in a different way. The first (pimm) is a positive offset and its range is different for the 32-bit variant and the 64-bit variant.
In the 32 bit version:
In the 64 bit version:
This means that some of the offsets combinations of LDUR and LDR (immediate) are going to produce the same operation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With