LDR is an ARM assembly language instruction that stands for “LoaD Register”. It is used to load a value from memory into a register. The LDR instruction copies the contents located at a specified memory address into a destination register.
ARM Registers
ARM processors contain general purpose registers that are used to store data and addresses for processing. Some key registers include:
- R0-R12 – General purpose registers
- SP – Stack pointer
- LR – Link register
- PC – Program counter
The LDR instruction loads a value from memory into one of the general purpose registers R0-R12. The syntax for LDR is: LDR Rd, [Rn, #offset]
Where:
- Rd – Destination register where the loaded value will be stored
- Rn – Base register containing the memory address to load from
- Offset – Optional offset from the base address Rn
LDR Usage
Here are some examples of using LDR in ARM assembly: LDR R1, [R2, #8]
This loads the 32-bit value from the memory address in R2 offset by 8 bytes into R1. LDR R3, =0x12345
This loads the 32-bit immediate value 0x12345 directly into R3. LDR R0, [R1], #4
This loads the value from the memory address in R1 into R0, and then increments R1 by 4 to point to the next word in memory. LDR R5, [R6, R7]
This uses R7 as an offset from the address in R6 to determine the final memory address to load from.
Loading Different Data Sizes
By default, LDR loads a 32-bit word into the destination register. However, different data sizes can be loaded using these variant instructions:
- LDRB – Load 8-bit byte
- LDRH – Load 16-bit halfword
- LDRSB – Load 8-bit signed byte
- LDRSH – Load 16-bit signed halfword
For example: LDRB R1, [R2, #1] // Load byte from R2 offset by 1 byte into R1 LDRH R3, [R4, #2] // Load unsigned 16-bit halfword from R4 offset by 2 bytes into R3
Load/Store Multiple
Loading or storing multiple registers can be done using LDM (LoaD Multiple) and STM (STore Multiple) instructions. For example: LDM R2!, {R1-R5} // Load R1-R5 from memory starting at R2, and increment R2 STM R3, {R6-R9} // Store R6-R9 to memory starting at R3
Addressing Modes
LDR supports several different addressing modes to specify the memory address being accessed:
- Offset – Add/subtract offset from base register
- Pre-indexed – Add offset to base before loading, store base + offset back into base register
- Post-indexed – Load from base, then add offset to base
- Register – Use value in register as offset
LDR R1, [R2, #-16] // Offset LDR R3, [R4, #8]! // Pre-indexed LDR R5, [R6], #4 // Post-indexed LDR R0, [R1, R7] // Register offset in R7
LDR vs LDRB vs LDRH
The main differences between LDR, LDRB, and LDRH:
- LDR loads a 32-bit word into a register
- LDRB loads an 8-bit byte into a register
- LDRH loads a 16-bit halfword into a register
LDRB and LDRH are useful for loading smaller data values from memory without the need to load a full 32-bit value.
Conditional Execution
The LDR instruction can be conditionally executed based on the status flags in the CPSR register: LDREQ R1, [R2, #0] // Load if Z set (equal) LDRNE R3, [R4, #8] // Load if Z clear (not equal)
This only performs the load if the condition is true. Conditional execution allows loads to be dependent on previous arithmetic or comparison results.
Typical Uses
Here are some common uses for the LDR instruction in ARM assembly programming:
- Loading data values from memory into registers for calculation
- Populating function arguments from the stack into registers
- Reading variable values from a data section into registers
- Loading constants or immediate values into registers
- Dereferencing pointers to access data at a specific memory address
- Loading registers as part of a context switch
- Transferring data blocks word by word or bytewise from memory
Overall, LDR provides an efficient way to transfer data from memory into registers for subsequent processing by the CPU.