4.2.1. LDR and STR, words and unsigned bytes

Load register and store register, 32-bit word or 8-bit unsigned byte. Byte loads are zero-extended to 32 bits.

Syntax

Both LDR and STR have four possible forms:

  • zero offset

  • pre-indexed offset

  • program-relative

  • post-indexed offset.

The syntax of the four forms, in the same order, are:

op{cond}{B}{T} Rd, [Rn]
op{cond}{B} Rd, [Rn, FlexOffset]{!}
op{cond}{B} Rd, label
op{cond}{B}{T} Rd, [Rn], FlexOffset

where:

op

is either LDR (Load Register)or STR (Store Register).

cond

is an optional condition code (see Conditional execution).

B

is an optional suffix. If B is present, the least significant byte of Rd is transferred. If op is LDR, the other bytes of Rd are cleared.

Otherwise, a 32-bit word is transferred.

T

is an optional suffix. If T is present, the memory system treats the access as though the processor was in User mode, even if it is in a privileged mode (see Processor mode). T has no effect in User mode. You cannot use T with a pre-indexed offset.

Rd

is the ARM register to load or save.

Rn

is the register on which the memory address is based.

Rn must not be the same as Rd, if the instruction:

  • is pre-indexed with writeback (the ! suffix)

  • is post-indexed

  • uses the T suffix.

FlexOffset

is a flexible offset applied to the value in Rn (see Flexible offset syntax).

label

is a program-relative expression. See Register-relative and program-relative expressions for more information.

label must be within ±4KB of the current instruction.

!

is an optional suffix. If ! is present, the address including the offset is written back into Rn. You cannot use the ! suffix if Rn is r15.

Zero offset

The value in Rn is used as the address for the transfer.

Pre-indexed offset

The offset is applied to the value in Rn before the data transfer takes place. The result is used as the memory address for the transfer. If the ! suffix is used, the result is written back into Rn. Rn must not be r15 if the !suffix is used.

Program-relative

This is an alternative version of the pre-indexed form. The assembler calculates the offset from the PC for you, and generates a pre-indexed instruction with the PC as Rn.

You cannot use the ! suffix.

Post-indexed offset

The value in Rn is used as the memory address for the transfer. The offset is applied to the value in Rn after the data transfer takes place. The result is written back into Rn. Rn must not be r15.

Flexible offset syntax

Both pre-indexed and post-indexed offsets can be either of the following:

#expr
{-}Rm{, shift}

where:

-

is an optional minus sign. If - is present, the offset is subtracted from Rn. Otherwise, the offset is added to Rn.

expr

is an expression evaluating to an integer in the range –4095 to +4095. This is often a numeric constant (see examples below).

Rm

is a register containing a value to be used as the offset. Rm must not be r15.

shift

is an optional shift to be applied to Rm. It can be any one of:

ASR n

arithmetic shift right n bits. 1 = n = 32.

LSL n

logical shift left n bits. 0 = n = 31.

LSR n

logical shift right n bits. 1 = n = 32.

ROR n

rotate right n bits. 1 = n = 31.

RRX

rotate right one bit, with extend.

Address alignment for word transfers

In most circumstances, you must ensure that addresses for 32-bit transfers are 32-bit word-aligned.

If your system has a system coprocessor (cp15), you can enable alignment checking. Non word-aligned 32-bit transfers cause an alignment exception if alignment checking is enabled.

If your system does not have a system coprocessor (cp15), or alignment checking is disabled:

  • For STR, the specified address is rounded down to a multiple of four.

  • For LDR:

    1. The specified address is rounded down to a multiple of four.

    2. Four bytes of data are loaded from the resulting address.

    3. The loaded data is rotated right by one, two or three bytes according to bits [1:0] of the address.

    For a little-endian memory system, this causes the addressed byte to occupy the least significant byte of the register.

    For a big-endian memory system, it causes the addressed byte to occupy:

    • bits[31:24] if bit[0] of the address is 0

    • bits[15:8] if bit[0] of the address is 1.

Loading to r15

A load to r15 (the program counter) causes a branch to the instruction at the address loaded.

Bits[1:0] of the value loaded:

  • are ignored in ARM architecture v3 and below

  • must be zero in ARM architecture v4.

In ARM architecture v5 and above:

  • bits[1:0] of a value loaded to r15 must not have the value 0b10

  • if bit[0] of a value loaded to r15 is set, the processor changes to Thumb state.

You cannot use the B or T suffixes when loading to r15.

Saving from r15

In general, avoid saving from r15 if possible.

If you do save from r15, the value saved is the address of the current instruction, plus an implementation-defined constant. The constant is always the same for a particular processor.

If your assembled code might be used on different processors, you can find out what the constant is at runtime using code like the following:

    SUB R1, PC, #4 ; R1 = address of following STR instruction
    STR PC, [R0]   ; Store address of STR instruction + offset,
    LDR R0, [R0]   ; then reload it
    SUB R0, R0, R1 ; Calculate the offset as the difference

If your code is to be assembled for a particular processor, the value of the constant is available in armasm as {PCSTOREOFFSET}.

Architectures

These instructions are available in all versions of the ARM architecture.

In T variants of ARM architecture v5 and above, a load to r15 causes a change to executing Thumb instructions if bit[0] of the value loaded is set.

Examples

    LDR     r8,[r10]            ; loads r8 from the address in r10.
    LDRNE   r2,[r5,#960]!       ; (conditionally) loads r2 from a word
                                ; 960 bytes above the address in r5, and
                                ; increments r5 by 960.
    STR     r2,[r9,#consta-struc]   ; consta-struc is an expression evaluating
                                    ; to a constant in the range 0-4095.
    STRB    r0,[r3,-r8,ASR #2]  ; stores the least significant byte from
                                ; r0 to a byte at an address equal to
                                ; contents(r3) minus contents(r8)/4.
                                ; r3 and r8 are not altered.
    STR     r5,[r7],#-8         ; stores a word from r5 to the address
                                ; in r7, and then decrements r7 by 8.
    LDR     r0,localdata        ; loads a word located at label localdata
Copyright © 2000, 2001 ARM Limited. All rights reserved.ARM DUI 0068B
Non-Confidential