LDUR and STUR in ARM v8

Plutonium picture Plutonium · Oct 19, 2018 · Viewed 15.4k times · Source

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?

Answer

Guillermo picture Guillermo · Oct 24, 2018

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:

  • It ranges from 0 to 16380 and can only be a multiple of 4

In the 64 bit version:

  • It ranges from 0 to 32760 and can only be a multiple of 8

This means that some of the offsets combinations of LDUR and LDR (immediate) are going to produce the same operation.